504 lines
15 KiB
JavaScript
504 lines
15 KiB
JavaScript
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
goog.provide('goog.testing.FunctionMockTest');
|
|
goog.setTestOnly('goog.testing.FunctionMockTest');
|
|
|
|
goog.require('goog.array');
|
|
goog.require('goog.string');
|
|
goog.require('goog.testing');
|
|
goog.require('goog.testing.FunctionMock');
|
|
goog.require('goog.testing.Mock');
|
|
goog.require('goog.testing.StrictMock');
|
|
goog.require('goog.testing.asserts');
|
|
goog.require('goog.testing.jsunit');
|
|
goog.require('goog.testing.mockmatchers');
|
|
|
|
// Global scope so we can tear it down safely
|
|
var mockGlobal;
|
|
|
|
function tearDown() {
|
|
if (mockGlobal) {
|
|
mockGlobal.$tearDown();
|
|
}
|
|
}
|
|
|
|
|
|
//----- Tests for goog.testing.FunctionMock
|
|
|
|
function testMockFunctionCallOrdering() {
|
|
var doOneTest = function(mockFunction, success, expected_args, actual_args) {
|
|
goog.array.forEach(expected_args, function(arg) { mockFunction(arg); });
|
|
mockFunction.$replay();
|
|
var callFunction = function() {
|
|
goog.array.forEach(actual_args, function(arg) { mockFunction(arg); });
|
|
mockFunction.$verify();
|
|
};
|
|
if (success) {
|
|
callFunction();
|
|
} else {
|
|
assertThrows(callFunction);
|
|
}
|
|
};
|
|
|
|
var doTest = function(strict_ok, loose_ok, expected_args, actual_args) {
|
|
doOneTest(goog.testing.createFunctionMock(), strict_ok,
|
|
expected_args, actual_args);
|
|
doOneTest(goog.testing.createFunctionMock('name'), strict_ok,
|
|
expected_args, actual_args);
|
|
doOneTest(goog.testing.createFunctionMock('name', goog.testing.Mock.STRICT),
|
|
strict_ok, expected_args, actual_args);
|
|
doOneTest(goog.testing.createFunctionMock('name', goog.testing.Mock.LOOSE),
|
|
loose_ok, expected_args, actual_args);
|
|
};
|
|
|
|
doTest(true, true, [1, 2], [1, 2]);
|
|
doTest(false, true, [1, 2], [2, 1]);
|
|
doTest(false, false, [1, 2], [2, 2]);
|
|
doTest(false, false, [1, 2], [1]);
|
|
doTest(false, false, [1, 2], [1, 1]);
|
|
doTest(false, false, [1, 2], [1]);
|
|
}
|
|
|
|
function testMocksFunctionWithNoArgs() {
|
|
var mockFoo = goog.testing.createFunctionMock();
|
|
mockFoo();
|
|
mockFoo.$replay();
|
|
mockFoo();
|
|
mockFoo.$verify();
|
|
}
|
|
|
|
function testMocksFunctionWithOneArg() {
|
|
var mockFoo = goog.testing.createFunctionMock();
|
|
mockFoo('x');
|
|
mockFoo.$replay();
|
|
mockFoo('x');
|
|
mockFoo.$verify();
|
|
}
|
|
|
|
function testMocksFunctionWithMultipleArgs() {
|
|
var mockFoo = goog.testing.createFunctionMock();
|
|
mockFoo('x', 'y');
|
|
mockFoo.$replay();
|
|
mockFoo('x', 'y');
|
|
mockFoo.$verify();
|
|
}
|
|
|
|
function testFailsIfCalledWithIncorrectArgs() {
|
|
var mockFoo = goog.testing.createFunctionMock();
|
|
|
|
mockFoo();
|
|
mockFoo.$replay();
|
|
assertThrows(function() {mockFoo('x');});
|
|
mockFoo.$reset();
|
|
|
|
mockFoo('x');
|
|
mockFoo.$replay();
|
|
assertThrows(function() {mockFoo();});
|
|
mockFoo.$reset();
|
|
|
|
mockFoo('x');
|
|
mockFoo.$replay();
|
|
assertThrows(function() {mockFoo('x', 'y');});
|
|
mockFoo.$reset();
|
|
|
|
mockFoo('x', 'y');
|
|
mockFoo.$replay();
|
|
assertThrows(function() {mockFoo('x');});
|
|
mockFoo.$reset();
|
|
|
|
mockFoo('correct');
|
|
mockFoo.$replay();
|
|
assertThrows(function() {mockFoo('wrong');});
|
|
mockFoo.$reset();
|
|
|
|
mockFoo('correct', 'args');
|
|
mockFoo.$replay();
|
|
assertThrows(function() {mockFoo('wrong', 'args');});
|
|
mockFoo.$reset();
|
|
}
|
|
|
|
function testMocksFunctionWithReturnValue() {
|
|
var mockFoo = goog.testing.createFunctionMock();
|
|
mockFoo().$returns('bar');
|
|
mockFoo.$replay();
|
|
assertEquals('bar', mockFoo());
|
|
mockFoo.$verify();
|
|
}
|
|
|
|
function testFunctionMockWorksWhenPassedAsACallback() {
|
|
var invoker = {
|
|
register: function(callback) {
|
|
this.callback = callback;
|
|
},
|
|
|
|
invoke: function(args) {
|
|
return this.callback(args);
|
|
}
|
|
};
|
|
|
|
var mockFunction = goog.testing.createFunctionMock();
|
|
mockFunction('bar').$returns('baz');
|
|
|
|
mockFunction.$replay();
|
|
invoker.register(mockFunction);
|
|
assertEquals('baz', invoker.invoke('bar'));
|
|
mockFunction.$verify();
|
|
}
|
|
|
|
function testFunctionMockQuacksLikeAStrictMock() {
|
|
var mockFunction = goog.testing.createFunctionMock();
|
|
assertQuacksLike(mockFunction, goog.testing.StrictMock);
|
|
}
|
|
|
|
|
|
//----- Global functions for goog.testing.GlobalFunctionMock to mock
|
|
|
|
function globalFoo() {
|
|
return 'I am Spartacus!';
|
|
}
|
|
|
|
function globalBar(who, what) {
|
|
return [who, 'is', what].join(' ');
|
|
}
|
|
|
|
|
|
//----- Tests for goog.testing.createGlobalFunctionMock
|
|
|
|
function testMocksGlobalFunctionWithNoArgs() {
|
|
mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
mockGlobal().$returns('No, I am Spartacus!');
|
|
|
|
mockGlobal.$replay();
|
|
assertEquals('No, I am Spartacus!', globalFoo());
|
|
mockGlobal.$verify();
|
|
}
|
|
|
|
function testMocksGlobalFunctionUsingGlobalName() {
|
|
goog.testing.createGlobalFunctionMock('globalFoo');
|
|
globalFoo().$returns('No, I am Spartacus!');
|
|
|
|
globalFoo.$replay();
|
|
assertEquals('No, I am Spartacus!', globalFoo());
|
|
globalFoo.$verify();
|
|
globalFoo.$tearDown();
|
|
}
|
|
|
|
function testMocksGlobalFunctionWithArgs() {
|
|
var mockReturnValue = 'Noam is Chomsky!';
|
|
mockGlobal = goog.testing.createGlobalFunctionMock('globalBar');
|
|
mockGlobal('Noam', 'Spartacus').$returns(mockReturnValue);
|
|
|
|
mockGlobal.$replay();
|
|
assertEquals(mockReturnValue, globalBar('Noam', 'Spartacus'));
|
|
mockGlobal.$verify();
|
|
}
|
|
|
|
function testGlobalFunctionMockFailsWithIncorrectArgs() {
|
|
mockGlobal = goog.testing.createGlobalFunctionMock('globalBar');
|
|
mockGlobal('a', 'b');
|
|
|
|
mockGlobal.$replay();
|
|
|
|
assertThrows('Mock should have failed because of incorrect arguments',
|
|
function() {globalBar('b', 'a')});
|
|
}
|
|
|
|
function testGlobalFunctionMockQuacksLikeAFunctionMock() {
|
|
mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
assertQuacksLike(mockGlobal, goog.testing.FunctionMock);
|
|
}
|
|
|
|
function testMockedFunctionsAvailableInGlobalAndGoogGlobalAndWindowScope() {
|
|
mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
|
|
// we expect this call 3 times through global, goog.global and window scope
|
|
mockGlobal().$times(3);
|
|
|
|
mockGlobal.$replay();
|
|
goog.global.globalFoo();
|
|
window.globalFoo();
|
|
globalFoo();
|
|
mockGlobal.$verify();
|
|
}
|
|
|
|
function testTearDownRestoresOriginalGlobalFunction() {
|
|
mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
mockGlobal().$returns('No, I am Spartacus!');
|
|
|
|
mockGlobal.$replay();
|
|
assertEquals('No, I am Spartacus!', globalFoo());
|
|
mockGlobal.$tearDown();
|
|
assertEquals('I am Spartacus!', globalFoo());
|
|
mockGlobal.$verify();
|
|
}
|
|
|
|
function testTearDownHandlesMultipleMocking() {
|
|
var mock1 = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
var mock2 = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
var mock3 = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
mock1().$returns('No, I am Spartacus 1!');
|
|
mock2().$returns('No, I am Spartacus 2!');
|
|
mock3().$returns('No, I am Spartacus 3!');
|
|
|
|
mock1.$replay();
|
|
mock2.$replay();
|
|
mock3.$replay();
|
|
assertEquals('No, I am Spartacus 3!', globalFoo());
|
|
mock3.$tearDown();
|
|
assertEquals('No, I am Spartacus 2!', globalFoo());
|
|
mock2.$tearDown();
|
|
assertEquals('No, I am Spartacus 1!', globalFoo());
|
|
mock1.$tearDown();
|
|
assertEquals('I am Spartacus!', globalFoo());
|
|
}
|
|
|
|
function testGlobalFunctionMockCallOrdering() {
|
|
var mock = goog.testing.createGlobalFunctionMock('globalFoo');
|
|
mock(1);
|
|
mock(2);
|
|
mock.$replay();
|
|
assertThrows(function() {globalFoo(2);});
|
|
mock.$tearDown();
|
|
|
|
mock = goog.testing.createGlobalFunctionMock('globalFoo',
|
|
goog.testing.Mock.STRICT);
|
|
mock(1);
|
|
mock(2);
|
|
mock.$replay();
|
|
globalFoo(1);
|
|
globalFoo(2);
|
|
mock.$verify();
|
|
mock.$tearDown();
|
|
|
|
mock = goog.testing.createGlobalFunctionMock('globalFoo',
|
|
goog.testing.Mock.STRICT);
|
|
mock(1);
|
|
mock(2);
|
|
mock.$replay();
|
|
assertThrows(function() {globalFoo(2);});
|
|
mock.$tearDown();
|
|
|
|
mock = goog.testing.createGlobalFunctionMock('globalFoo',
|
|
goog.testing.Mock.LOOSE);
|
|
mock(1);
|
|
mock(2);
|
|
mock.$replay();
|
|
globalFoo(2);
|
|
globalFoo(1);
|
|
mock.$verify();
|
|
mock.$tearDown();
|
|
}
|
|
|
|
//----- Functions for goog.testing.MethodMock to mock
|
|
|
|
var mynamespace = {};
|
|
|
|
mynamespace.myMethod = function() {
|
|
return 'I should be mocked.';
|
|
};
|
|
|
|
function testMocksMethod() {
|
|
mockMethod = goog.testing.createMethodMock(mynamespace, 'myMethod');
|
|
mockMethod().$returns('I have been mocked!');
|
|
|
|
mockMethod.$replay();
|
|
assertEquals('I have been mocked!', mockMethod());
|
|
mockMethod.$verify();
|
|
}
|
|
|
|
function testMocksMethodInNamespace() {
|
|
goog.testing.createMethodMock(mynamespace, 'myMethod');
|
|
mynamespace.myMethod().$returns('I have been mocked!');
|
|
|
|
mynamespace.myMethod.$replay();
|
|
assertEquals('I have been mocked!', mynamespace.myMethod());
|
|
mynamespace.myMethod.$verify();
|
|
mynamespace.myMethod.$tearDown();
|
|
}
|
|
|
|
function testMethodMockCanOnlyMockExistingMethods() {
|
|
assertThrows(function() {
|
|
goog.testing.createMethodMock(mynamespace, 'doesNotExist');
|
|
});
|
|
}
|
|
|
|
function testMethodMockCallOrdering() {
|
|
goog.testing.createMethodMock(mynamespace, 'myMethod');
|
|
mynamespace.myMethod(1);
|
|
mynamespace.myMethod(2);
|
|
mynamespace.myMethod.$replay();
|
|
assertThrows(function() {mynamespace.myMethod(2);});
|
|
mynamespace.myMethod.$tearDown();
|
|
|
|
goog.testing.createMethodMock(mynamespace, 'myMethod',
|
|
goog.testing.Mock.STRICT);
|
|
mynamespace.myMethod(1);
|
|
mynamespace.myMethod(2);
|
|
mynamespace.myMethod.$replay();
|
|
mynamespace.myMethod(1);
|
|
mynamespace.myMethod(2);
|
|
mynamespace.myMethod.$verify();
|
|
mynamespace.myMethod.$tearDown();
|
|
|
|
goog.testing.createMethodMock(mynamespace, 'myMethod',
|
|
goog.testing.Mock.STRICT);
|
|
mynamespace.myMethod(1);
|
|
mynamespace.myMethod(2);
|
|
mynamespace.myMethod.$replay();
|
|
assertThrows(function() {mynamespace.myMethod(2);});
|
|
mynamespace.myMethod.$tearDown();
|
|
|
|
goog.testing.createMethodMock(mynamespace, 'myMethod',
|
|
goog.testing.Mock.LOOSE);
|
|
mynamespace.myMethod(1);
|
|
mynamespace.myMethod(2);
|
|
mynamespace.myMethod.$replay();
|
|
mynamespace.myMethod(2);
|
|
mynamespace.myMethod(1);
|
|
mynamespace.myMethod.$verify();
|
|
mynamespace.myMethod.$tearDown();
|
|
}
|
|
|
|
//----- Functions for goog.testing.createConstructorMock to mock
|
|
|
|
var constructornamespace = {};
|
|
|
|
constructornamespace.MyConstructor = function() {
|
|
};
|
|
|
|
constructornamespace.MyConstructor.prototype.myMethod = function() {
|
|
return 'I should be mocked.';
|
|
};
|
|
|
|
constructornamespace.MyConstructorWithArgument = function(argument) {
|
|
this.argument_ = argument;
|
|
};
|
|
|
|
constructornamespace.MyConstructorWithArgument.prototype.myMethod = function() {
|
|
return this.argument_;
|
|
};
|
|
|
|
constructornamespace.MyConstructorWithClassMembers = function() {
|
|
};
|
|
|
|
constructornamespace.MyConstructorWithClassMembers.CONSTANT = 42;
|
|
|
|
constructornamespace.MyConstructorWithClassMembers.classMethod = function() {
|
|
return 'class method return value';
|
|
};
|
|
|
|
function testConstructorMock() {
|
|
var mockObject =
|
|
new goog.testing.StrictMock(constructornamespace.MyConstructor);
|
|
var mockConstructor = goog.testing.createConstructorMock(
|
|
constructornamespace, 'MyConstructor');
|
|
mockConstructor().$returns(mockObject);
|
|
mockObject.myMethod().$returns('I have been mocked!');
|
|
|
|
mockConstructor.$replay();
|
|
mockObject.$replay();
|
|
assertEquals('I have been mocked!',
|
|
new constructornamespace.MyConstructor().myMethod());
|
|
mockConstructor.$verify();
|
|
mockObject.$verify();
|
|
mockConstructor.$tearDown();
|
|
}
|
|
|
|
function testConstructorMockWithArgument() {
|
|
var mockObject = new goog.testing.StrictMock(
|
|
constructornamespace.MyConstructorWithArgument);
|
|
var mockConstructor = goog.testing.createConstructorMock(
|
|
constructornamespace, 'MyConstructorWithArgument');
|
|
mockConstructor(goog.testing.mockmatchers.isString).$returns(mockObject);
|
|
mockObject.myMethod().$returns('I have been mocked!');
|
|
|
|
mockConstructor.$replay();
|
|
mockObject.$replay();
|
|
assertEquals('I have been mocked!',
|
|
new constructornamespace.MyConstructorWithArgument('I should be mocked.')
|
|
.myMethod());
|
|
mockConstructor.$verify();
|
|
mockObject.$verify();
|
|
mockConstructor.$tearDown();
|
|
}
|
|
|
|
|
|
/**
|
|
* Test that class members are copied to the mock constructor.
|
|
*/
|
|
function testConstructorMockWithClassMembers() {
|
|
var mockConstructor = goog.testing.createConstructorMock(
|
|
constructornamespace, 'MyConstructorWithClassMembers');
|
|
assertEquals(42, constructornamespace.MyConstructorWithClassMembers.CONSTANT);
|
|
assertEquals('class method return value',
|
|
constructornamespace.MyConstructorWithClassMembers.classMethod());
|
|
mockConstructor.$tearDown();
|
|
}
|
|
|
|
function testConstructorMockCallOrdering() {
|
|
var instance = {};
|
|
|
|
goog.testing.createConstructorMock(constructornamespace,
|
|
'MyConstructorWithArgument');
|
|
constructornamespace.MyConstructorWithArgument(1).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument(2).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument.$replay();
|
|
assertThrows(
|
|
function() {new constructornamespace.MyConstructorWithArgument(2);});
|
|
constructornamespace.MyConstructorWithArgument.$tearDown();
|
|
|
|
goog.testing.createConstructorMock(constructornamespace,
|
|
'MyConstructorWithArgument',
|
|
goog.testing.Mock.STRICT);
|
|
constructornamespace.MyConstructorWithArgument(1).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument(2).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument.$replay();
|
|
new constructornamespace.MyConstructorWithArgument(1);
|
|
new constructornamespace.MyConstructorWithArgument(2);
|
|
constructornamespace.MyConstructorWithArgument.$verify();
|
|
constructornamespace.MyConstructorWithArgument.$tearDown();
|
|
|
|
goog.testing.createConstructorMock(constructornamespace,
|
|
'MyConstructorWithArgument',
|
|
goog.testing.Mock.STRICT);
|
|
constructornamespace.MyConstructorWithArgument(1).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument(2).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument.$replay();
|
|
assertThrows(
|
|
function() {new constructornamespace.MyConstructorWithArgument(2);});
|
|
constructornamespace.MyConstructorWithArgument.$tearDown();
|
|
|
|
goog.testing.createConstructorMock(constructornamespace,
|
|
'MyConstructorWithArgument',
|
|
goog.testing.Mock.LOOSE);
|
|
constructornamespace.MyConstructorWithArgument(1).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument(2).$returns(instance);
|
|
constructornamespace.MyConstructorWithArgument.$replay();
|
|
new constructornamespace.MyConstructorWithArgument(2);
|
|
new constructornamespace.MyConstructorWithArgument(1);
|
|
constructornamespace.MyConstructorWithArgument.$verify();
|
|
constructornamespace.MyConstructorWithArgument.$tearDown();
|
|
}
|
|
|
|
//----- Helper assertions
|
|
|
|
function assertQuacksLike(obj, target) {
|
|
for (meth in target.prototype) {
|
|
if (!goog.string.endsWith(meth, '_')) {
|
|
assertNotUndefined('Should have implemented ' + meth + '()', obj[meth]);
|
|
}
|
|
}
|
|
}
|