| // 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.LooseMockTest'); |
| goog.setTestOnly('goog.testing.LooseMockTest'); |
| |
| goog.require('goog.testing.LooseMock'); |
| goog.require('goog.testing.PropertyReplacer'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.testing.mockmatchers'); |
| |
| // 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 mock; |
| |
| var stubs; |
| |
| function setUp() { |
| var obj = new RealObject(); |
| mock = new goog.testing.LooseMock(obj); |
| stubs = new goog.testing.PropertyReplacer(); |
| } |
| |
| function tearDown() { |
| stubs.reset(); |
| } |
| |
| /* |
| * Calling this method evades the logTestFailure in |
| * goog.testing.Mock.prototype.$recordAndThrow, so it doesn't look like the |
| * test failed. |
| */ |
| function silenceFailureLogging() { |
| if (goog.global['G_testRunner']) { |
| stubs.set(goog.global['G_testRunner'], |
| 'logTestFailure', goog.nullFunction); |
| } |
| } |
| |
| function unsilenceFailureLogging() { |
| stubs.reset(); |
| } |
| |
| |
| /** |
| * Version of assertThrows that doesn't log the exception generated by the |
| * mocks under test. |
| * TODO: would be nice to check that a particular substring is in the thrown |
| * message so we know it's not something dumb like a syntax error |
| */ |
| function assertThrowsQuiet(var_args) { |
| silenceFailureLogging(); |
| assertThrows.apply(null, arguments); |
| unsilenceFailureLogging(); |
| } |
| |
| // Most of the basic functionality is tested in strictmock_test; these tests |
| // cover the cases where loose mocks are different from strict mocks |
| function testSimpleExpectations() { |
| mock.a(5); |
| mock.b(); |
| mock.$replay(); |
| mock.a(5); |
| mock.b(); |
| mock.$verify(); |
| |
| mock.$reset(); |
| |
| mock.a(); |
| mock.b(); |
| mock.$replay(); |
| mock.b(); |
| mock.a(); |
| mock.$verify(); |
| |
| mock.$reset(); |
| |
| mock.a(5).$times(2); |
| mock.a(5); |
| mock.a(2); |
| mock.$replay(); |
| mock.a(5); |
| mock.a(5); |
| mock.a(5); |
| mock.a(2); |
| mock.$verify(); |
| } |
| |
| |
| function testMultipleExpectations() { |
| mock.a().$returns(1); |
| mock.a().$returns(2); |
| mock.$replay(); |
| assertEquals(1, mock.a()); |
| assertEquals(2, mock.a()); |
| mock.$verify(); |
| } |
| |
| |
| function testMultipleExpectationArgs() { |
| mock.a('asdf').$anyTimes(); |
| mock.a('qwer').$anyTimes(); |
| mock.b().$times(3); |
| mock.$replay(); |
| mock.a('asdf'); |
| mock.b(); |
| mock.a('asdf'); |
| mock.a('qwer'); |
| mock.b(); |
| mock.a('qwer'); |
| mock.b(); |
| mock.$verify(); |
| |
| mock.$reset(); |
| |
| mock.a('asdf').$anyTimes(); |
| mock.a('qwer').$anyTimes(); |
| mock.$replay(); |
| mock.a('asdf'); |
| mock.a('qwer'); |
| goog.bind(mock.a, mock, 'asdf'); |
| goog.bind(mock.$verify, mock); |
| } |
| |
| function testSameMethodOutOfOrder() { |
| mock.a('foo').$returns(1); |
| mock.a('bar').$returns(2); |
| mock.$replay(); |
| assertEquals(2, mock.a('bar')); |
| assertEquals(1, mock.a('foo')); |
| } |
| |
| function testSameMethodDifferentReturnValues() { |
| mock.a('foo').$returns(1).$times(2); |
| mock.a('foo').$returns(3); |
| mock.a('bar').$returns(2); |
| mock.$replay(); |
| assertEquals(1, mock.a('foo')); |
| assertEquals(2, mock.a('bar')); |
| assertEquals(1, mock.a('foo')); |
| assertEquals(3, mock.a('foo')); |
| assertThrowsQuiet(function() { |
| mock.a('foo'); |
| mock.$verify(); |
| }); |
| } |
| |
| function testSameMethodBrokenExpectations() { |
| // This is a weird corner case. |
| // No way to ever make this verify no matter what you call after replaying, |
| // because the second expectation of mock.a('foo') will be masked by |
| // the first expectation that can be called any number of times, and so we |
| // can never satisfy that second expectation. |
| mock.a('foo').$returns(1).$anyTimes(); |
| mock.a('bar').$returns(2); |
| mock.a('foo').$returns(3); |
| |
| // LooseMock can detect this case and fail on $replay. |
| assertThrowsQuiet(goog.bind(mock.$replay, mock)); |
| mock.$reset(); |
| |
| // This is a variant of the corner case above, but it's harder to determine |
| // that the expectation to mock.a('bar') can never be satisfied. So we don't |
| // fail on $replay, but we do fail on $verify. |
| mock.a(goog.testing.mockmatchers.isString).$returns(1).$anyTimes(); |
| mock.a('bar').$returns(2); |
| mock.$replay(); |
| |
| assertEquals(1, mock.a('foo')); |
| assertEquals(1, mock.a('bar')); |
| assertThrowsQuiet(goog.bind(mock.$verify, mock)); |
| } |
| |
| function testSameMethodMultipleAnyTimes() { |
| mock.a('foo').$returns(1).$anyTimes(); |
| mock.a('foo').$returns(2).$anyTimes(); |
| mock.$replay(); |
| assertEquals(1, mock.a('foo')); |
| assertEquals(1, mock.a('foo')); |
| assertEquals(1, mock.a('foo')); |
| // Note we'll never return 2 but that's ok. |
| mock.$verify(); |
| } |
| |
| function testFailingFast() { |
| mock.a().$anyTimes(); |
| mock.$replay(); |
| mock.a(); |
| mock.a(); |
| assertThrowsQuiet(goog.bind(mock.b, mock)); |
| mock.$reset(); |
| |
| // too many |
| mock.a(); |
| mock.b(); |
| mock.$replay(); |
| mock.a(); |
| mock.b(); |
| |
| var message; |
| silenceFailureLogging(); |
| try { |
| mock.a(); |
| } catch (e) { |
| message = e.message; |
| } |
| unsilenceFailureLogging(); |
| |
| assertTrue('No exception thrown on unexpected call', goog.isDef(message)); |
| assertContains('Too many calls to a', message); |
| } |
| |
| function testTimes() { |
| mock.a().$times(3); |
| mock.b().$times(2); |
| mock.$replay(); |
| mock.a(); |
| mock.b(); |
| mock.b(); |
| mock.a(); |
| mock.a(); |
| mock.$verify(); |
| } |
| |
| |
| function testFailingSlow() { |
| // not enough |
| mock.a().$times(3); |
| mock.$replay(); |
| mock.a(); |
| mock.a(); |
| assertThrowsQuiet(goog.bind(mock.$verify, mock)); |
| |
| mock.$reset(); |
| |
| // not enough, interleaved order |
| mock.a().$times(3); |
| mock.b().$times(3); |
| mock.$replay(); |
| mock.a(); |
| mock.b(); |
| mock.a(); |
| mock.b(); |
| assertThrowsQuiet(goog.bind(mock.$verify, mock)); |
| |
| mock.$reset(); |
| // bad args |
| mock.a('asdf').$anyTimes(); |
| mock.$replay(); |
| mock.a('asdf'); |
| assertThrowsQuiet(goog.bind(mock.a, mock, 'qwert')); |
| assertThrowsQuiet(goog.bind(mock.$verify, mock)); |
| } |
| |
| |
| function testArgsAndReturns() { |
| mock.a('asdf').$atLeastOnce().$returns(5); |
| mock.b('qwer').$times(2).$returns(3); |
| mock.$replay(); |
| assertEquals(5, mock.a('asdf')); |
| assertEquals(3, mock.b('qwer')); |
| assertEquals(5, mock.a('asdf')); |
| assertEquals(5, mock.a('asdf')); |
| assertEquals(3, mock.b('qwer')); |
| mock.$verify(); |
| } |
| |
| |
| function testThrows() { |
| mock.a().$throws('exception!'); |
| mock.$replay(); |
| assertThrowsQuiet(goog.bind(mock.a, mock)); |
| mock.$verify(); |
| } |
| |
| |
| function testDoes() { |
| mock.a(1, 2).$does(function(a, b) {return a + b;}); |
| mock.$replay(); |
| assertEquals('Mock should call the function', 3, mock.a(1, 2)); |
| mock.$verify(); |
| } |
| |
| function testIgnoresExtraCalls() { |
| mock = new goog.testing.LooseMock(RealObject, true); |
| mock.a(); |
| mock.$replay(); |
| mock.a(); |
| mock.b(); // doesn't throw |
| mock.$verify(); |
| } |
| |
| function testSkipAnyTimes() { |
| mock = new goog.testing.LooseMock(RealObject); |
| mock.a(1).$anyTimes(); |
| mock.a(2).$anyTimes(); |
| mock.a(3).$anyTimes(); |
| mock.$replay(); |
| mock.a(1); |
| mock.a(3); |
| mock.$verify(); |
| } |
| |
| function testErrorMessageForBadArgs() { |
| mock.a(); |
| mock.$anyTimes(); |
| |
| mock.$replay(); |
| |
| var message; |
| silenceFailureLogging(); |
| try { |
| mock.a('a'); |
| } catch (e) { |
| message = e.message; |
| } |
| unsilenceFailureLogging(); |
| |
| assertTrue('No exception thrown on verify', goog.isDef(message)); |
| assertContains('Bad arguments to a()', message); |
| } |