| // 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.MockTest'); |
| goog.setTestOnly('goog.testing.MockTest'); |
| |
| goog.require('goog.array'); |
| goog.require('goog.testing'); |
| goog.require('goog.testing.Mock'); |
| goog.require('goog.testing.MockControl'); |
| goog.require('goog.testing.MockExpectation'); |
| goog.require('goog.testing.jsunit'); |
| |
| // The object that we will be mocking |
| var RealObject = function() { |
| }; |
| |
| RealObject.prototype.a = function() { |
| fail('real object should never be called'); |
| }; |
| |
| RealObject.prototype.b = function() { |
| fail('real object should never be called'); |
| }; |
| |
| var matchers = goog.testing.mockmatchers; |
| var mock; |
| |
| function setUp() { |
| var obj = new RealObject(); |
| mock = new goog.testing.Mock(obj); |
| } |
| |
| function testMockErrorMessage() { |
| var expectation = new goog.testing.MockExpectation('a'); |
| assertEquals(0, expectation.getErrorMessageCount()); |
| assertEquals('', expectation.getErrorMessage()); |
| |
| expectation.addErrorMessage('foo failed'); |
| assertEquals(1, expectation.getErrorMessageCount()); |
| assertEquals('foo failed', expectation.getErrorMessage()); |
| |
| expectation.addErrorMessage('bar failed'); |
| assertEquals(2, expectation.getErrorMessageCount()); |
| assertEquals('foo failed\nbar failed', expectation.getErrorMessage()); |
| } |
| |
| function testVerifyArgumentList() { |
| var expectation = new goog.testing.MockExpectation('a'); |
| assertEquals('', expectation.getErrorMessage()); |
| |
| // test single string arg |
| expectation.argumentList = ['foo']; |
| assertTrue(mock.$verifyCall(expectation, 'a', ['foo'])); |
| |
| // single numeric arg |
| expectation.argumentList = [2]; |
| assertTrue(mock.$verifyCall(expectation, 'a', [2])); |
| |
| // single object arg (using standard === comparison) |
| var obj = {prop1: 'prop1', prop2: 2}; |
| expectation.argumentList = [obj]; |
| assertTrue(mock.$verifyCall(expectation, 'a', [obj])); |
| |
| // make sure comparison succeeds if args are similar, but not === |
| var obj2 = {prop1: 'prop1', prop2: 2}; |
| expectation.argumentList = [obj]; |
| assertTrue(mock.$verifyCall(expectation, 'a', [obj2])); |
| assertEquals('', expectation.getErrorMessage()); |
| |
| // multiple args |
| expectation.argumentList = ['foo', 2, obj, obj2]; |
| assertTrue(mock.$verifyCall(expectation, 'a', ['foo', 2, obj, obj2])); |
| |
| // test flexible arg matching. |
| expectation.argumentList = ['foo', matchers.isNumber]; |
| assertTrue(mock.$verifyCall(expectation, 'a', ['foo', 1])); |
| |
| expectation.argumentList = [new matchers.InstanceOf(RealObject)]; |
| assertTrue(mock.$verifyCall(expectation, 'a', [new RealObject()])); |
| } |
| |
| function testVerifyArgumentListForObjectMethods() { |
| var expectation = new goog.testing.MockExpectation('toString'); |
| expectation.argumentList = []; |
| assertTrue(mock.$verifyCall(expectation, 'toString', [])); |
| } |
| |
| function testRegisterArgumentListVerifier() { |
| var expectationA = new goog.testing.MockExpectation('a'); |
| var expectationB = new goog.testing.MockExpectation('b'); |
| |
| // Simple matcher that return true if all args are === equivalent. |
| mock.$registerArgumentListVerifier('a', function(expectedArgs, args) { |
| return goog.array.equals(expectedArgs, args, function(a, b) { |
| return (a === b); |
| }); |
| }); |
| |
| // test single string arg |
| expectationA.argumentList = ['foo']; |
| assertTrue(mock.$verifyCall(expectationA, 'a', ['foo'])); |
| |
| // single numeric arg |
| expectationA.argumentList = [2]; |
| assertTrue(mock.$verifyCall(expectationA, 'a', [2])); |
| |
| // single object arg (using standard === comparison) |
| var obj = {prop1: 'prop1', prop2: 2}; |
| expectationA.argumentList = [obj]; |
| expectationB.argumentList = [obj]; |
| assertTrue(mock.$verifyCall(expectationA, 'a', [obj])); |
| assertTrue(mock.$verifyCall(expectationB, 'b', [obj])); |
| |
| // if args are similar, but not ===, then comparison should succeed |
| // for method with registered object matcher, and fail for method without |
| var obj2 = {prop1: 'prop1', prop2: 2}; |
| expectationA.argumentList = [obj]; |
| expectationB.argumentList = [obj]; |
| assertFalse(mock.$verifyCall(expectationA, 'a', [obj2])); |
| assertTrue(mock.$verifyCall(expectationB, 'b', [obj2])); |
| |
| |
| // multiple args, should fail for method with registered arg matcher, |
| // and succeed for method without. |
| expectationA.argumentList = ['foo', 2, obj, obj2]; |
| expectationB.argumentList = ['foo', 2, obj, obj2]; |
| assertFalse(mock.$verifyCall(expectationA, 'a', ['foo', 2, obj2, obj])); |
| assertTrue(mock.$verifyCall(expectationB, 'b', ['foo', 2, obj2, obj])); |
| } |
| |
| |
| function testCreateProxy() { |
| mock = new goog.testing.Mock(RealObject, false, true); |
| assertTrue(mock.$proxy instanceof RealObject); |
| assertThrows(function() { |
| new goog.testing.Mock(RealObject, true, true); |
| }); |
| assertThrows(function() { |
| new goog.testing.Mock(1, false, true); |
| }); |
| } |
| |
| |
| function testValidConstructorArgument() { |
| var someNamespace = { }; |
| assertThrows(function() { |
| new goog.testing.Mock(someNamespace.RealObjectWithTypo); |
| }); |
| } |
| |
| |
| function testArgumentsAsString() { |
| assertEquals('()', mock.$argumentsAsString([])); |
| assertEquals('(string, number, object, null)', |
| mock.$argumentsAsString(['red', 1, {}, null])); |
| } |
| |
| |
| function testThrowCallExceptionBadArgs() { |
| var msg; |
| mock.$throwException = function(m) { |
| msg = m; |
| }; |
| |
| mock.$throwCallException( |
| 'fn1', ['b'], |
| { name: 'fn1', |
| argumentList: ['c'], |
| getErrorMessage: function() { return ''; } }); |
| assertContains( |
| 'Bad arguments to fn1().\nActual: (string)\nExpected: (string)', msg); |
| } |
| |
| function testThrowCallExceptionUnexpected() { |
| var msg; |
| mock.$throwException = function(m) { |
| msg = m; |
| }; |
| |
| mock.$throwCallException('fn1', ['b']); |
| assertEquals('Unexpected call to fn1(string).', msg); |
| } |
| |
| function testThrowCallExceptionUnexpectedWithNext() { |
| var msg; |
| mock.$throwException = function(m) { |
| msg = m; |
| }; |
| |
| mock.$throwCallException( |
| 'fn1', ['b'], |
| { name: 'fn2', |
| argumentList: [3], |
| getErrorMessage: function() { return ''; } }); |
| assertEquals( |
| 'Unexpected call to fn1(string).\n' + |
| 'Next expected call was to fn2(number)', msg); |
| } |
| |
| // This tests that base Object functions which are not enumerable in IE can |
| // be mocked correctly. |
| function testBindNonEnumerableFunctions() { |
| // Create Foo and override non enumerable functions. |
| var Foo = function() {}; |
| Foo.prototype.constructor = function() { |
| fail('real object should never be called'); |
| }; |
| Foo.prototype.hasOwnProperty = function() { |
| fail('real object should never be called'); |
| }; |
| Foo.prototype.isPrototypeOf = function() { |
| fail('real object should never be called'); |
| }; |
| Foo.prototype.propertyIsEnumerable = function() { |
| fail('real object should never be called'); |
| }; |
| Foo.prototype.toLocaleString = function() { |
| fail('real object should never be called'); |
| }; |
| Foo.prototype.toString = function() { |
| fail('real object should never be called'); |
| }; |
| Foo.prototype.valueOf = function() { |
| fail('real object should never be called'); |
| }; |
| |
| // Create Mock and set $returns for toString. |
| var mockControl = new goog.testing.MockControl(); |
| var mock = mockControl.createLooseMock(Foo); |
| mock.constructor().$returns('constructor'); |
| mock.hasOwnProperty().$returns('hasOwnProperty'); |
| mock.isPrototypeOf().$returns('isPrototypeOf'); |
| mock.propertyIsEnumerable().$returns('propertyIsEnumerable'); |
| mock.toLocaleString().$returns('toLocaleString'); |
| mock.toString().$returns('toString'); |
| mock.valueOf().$returns('valueOf'); |
| |
| // Execute and assert that the Mock is working correctly. |
| mockControl.$replayAll(); |
| assertEquals('constructor', mock.constructor()); |
| assertEquals('hasOwnProperty', mock.hasOwnProperty()); |
| assertEquals('isPrototypeOf', mock.isPrototypeOf()); |
| assertEquals('propertyIsEnumerable', mock.propertyIsEnumerable()); |
| assertEquals('toLocaleString', mock.toLocaleString()); |
| assertEquals('toString', mock.toString()); |
| assertEquals('valueOf', mock.valueOf()); |
| mockControl.$verifyAll(); |
| } |