mock_test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.testing.MockTest');
  15. goog.setTestOnly('goog.testing.MockTest');
  16. goog.require('goog.array');
  17. goog.require('goog.testing');
  18. goog.require('goog.testing.Mock');
  19. goog.require('goog.testing.MockControl');
  20. goog.require('goog.testing.MockExpectation');
  21. goog.require('goog.testing.jsunit');
  22. // The object that we will be mocking
  23. var RealObject = function() {};
  24. RealObject.prototype.a = function() {
  25. fail('real object should never be called');
  26. };
  27. RealObject.prototype.b = function() {
  28. fail('real object should never be called');
  29. };
  30. var matchers = goog.testing.mockmatchers;
  31. var mock;
  32. function setUp() {
  33. var obj = new RealObject();
  34. mock = new goog.testing.Mock(obj);
  35. }
  36. function testMockErrorMessage() {
  37. var expectation = new goog.testing.MockExpectation('a');
  38. assertEquals(0, expectation.getErrorMessageCount());
  39. assertEquals('', expectation.getErrorMessage());
  40. expectation.addErrorMessage('foo failed');
  41. assertEquals(1, expectation.getErrorMessageCount());
  42. assertEquals('foo failed', expectation.getErrorMessage());
  43. expectation.addErrorMessage('bar failed');
  44. assertEquals(2, expectation.getErrorMessageCount());
  45. assertEquals('foo failed\nbar failed', expectation.getErrorMessage());
  46. }
  47. function testVerifyArgumentList() {
  48. var expectation = new goog.testing.MockExpectation('a');
  49. assertEquals('', expectation.getErrorMessage());
  50. // test single string arg
  51. expectation.argumentList = ['foo'];
  52. assertTrue(mock.$verifyCall(expectation, 'a', ['foo']));
  53. // single numeric arg
  54. expectation.argumentList = [2];
  55. assertTrue(mock.$verifyCall(expectation, 'a', [2]));
  56. // single object arg (using standard === comparison)
  57. var obj = {prop1: 'prop1', prop2: 2};
  58. expectation.argumentList = [obj];
  59. assertTrue(mock.$verifyCall(expectation, 'a', [obj]));
  60. // make sure comparison succeeds if args are similar, but not ===
  61. var obj2 = {prop1: 'prop1', prop2: 2};
  62. expectation.argumentList = [obj];
  63. assertTrue(mock.$verifyCall(expectation, 'a', [obj2]));
  64. assertEquals('', expectation.getErrorMessage());
  65. // multiple args
  66. expectation.argumentList = ['foo', 2, obj, obj2];
  67. assertTrue(mock.$verifyCall(expectation, 'a', ['foo', 2, obj, obj2]));
  68. // test flexible arg matching.
  69. expectation.argumentList = ['foo', matchers.isNumber];
  70. assertTrue(mock.$verifyCall(expectation, 'a', ['foo', 1]));
  71. expectation.argumentList = [new matchers.InstanceOf(RealObject)];
  72. assertTrue(mock.$verifyCall(expectation, 'a', [new RealObject()]));
  73. }
  74. function testVerifyArgumentListForObjectMethods() {
  75. var expectation = new goog.testing.MockExpectation('toString');
  76. expectation.argumentList = [];
  77. assertTrue(mock.$verifyCall(expectation, 'toString', []));
  78. }
  79. function testRegisterArgumentListVerifier() {
  80. var expectationA = new goog.testing.MockExpectation('a');
  81. var expectationB = new goog.testing.MockExpectation('b');
  82. // Simple matcher that return true if all args are === equivalent.
  83. mock.$registerArgumentListVerifier('a', function(expectedArgs, args) {
  84. return goog.array.equals(
  85. expectedArgs, args, function(a, b) { return (a === b); });
  86. });
  87. // test single string arg
  88. expectationA.argumentList = ['foo'];
  89. assertTrue(mock.$verifyCall(expectationA, 'a', ['foo']));
  90. // single numeric arg
  91. expectationA.argumentList = [2];
  92. assertTrue(mock.$verifyCall(expectationA, 'a', [2]));
  93. // single object arg (using standard === comparison)
  94. var obj = {prop1: 'prop1', prop2: 2};
  95. expectationA.argumentList = [obj];
  96. expectationB.argumentList = [obj];
  97. assertTrue(mock.$verifyCall(expectationA, 'a', [obj]));
  98. assertTrue(mock.$verifyCall(expectationB, 'b', [obj]));
  99. // if args are similar, but not ===, then comparison should succeed
  100. // for method with registered object matcher, and fail for method without
  101. var obj2 = {prop1: 'prop1', prop2: 2};
  102. expectationA.argumentList = [obj];
  103. expectationB.argumentList = [obj];
  104. assertFalse(mock.$verifyCall(expectationA, 'a', [obj2]));
  105. assertTrue(mock.$verifyCall(expectationB, 'b', [obj2]));
  106. // multiple args, should fail for method with registered arg matcher,
  107. // and succeed for method without.
  108. expectationA.argumentList = ['foo', 2, obj, obj2];
  109. expectationB.argumentList = ['foo', 2, obj, obj2];
  110. assertFalse(mock.$verifyCall(expectationA, 'a', ['foo', 2, obj2, obj]));
  111. assertTrue(mock.$verifyCall(expectationB, 'b', ['foo', 2, obj2, obj]));
  112. }
  113. function testCreateProxy() {
  114. mock = new goog.testing.Mock(RealObject, false, true);
  115. assertTrue(mock.$proxy instanceof RealObject);
  116. assertThrows(function() { new goog.testing.Mock(RealObject, true, true); });
  117. assertThrows(function() { new goog.testing.Mock(1, false, true); });
  118. }
  119. function testValidConstructorArgument() {
  120. var someNamespace = {};
  121. assertThrows(function() {
  122. new goog.testing.Mock(someNamespace.RealObjectWithTypo);
  123. });
  124. }
  125. function testArgumentsAsString() {
  126. assertEquals('()', mock.$argumentsAsString([]));
  127. assertEquals(
  128. '(string, number, object, null)',
  129. mock.$argumentsAsString(['red', 1, {}, null]));
  130. }
  131. function testThrowCallExceptionBadArgs() {
  132. var msg;
  133. mock.$throwException = function(m) { msg = m; };
  134. mock.$throwCallException('fn1', ['b'], {
  135. name: 'fn1',
  136. argumentList: ['c'],
  137. getErrorMessage: function() { return ''; }
  138. });
  139. assertContains(
  140. 'Bad arguments to fn1().\nActual: (string)\nExpected: (string)', msg);
  141. }
  142. function testThrowCallExceptionUnexpected() {
  143. var msg;
  144. mock.$throwException = function(m) { msg = m; };
  145. mock.$throwCallException('fn1', ['b']);
  146. assertEquals('Unexpected call to fn1(string).', msg);
  147. }
  148. function testThrowCallExceptionUnexpectedWithNext() {
  149. var msg;
  150. mock.$throwException = function(m) { msg = m; };
  151. mock.$throwCallException('fn1', ['b'], {
  152. name: 'fn2',
  153. argumentList: [3],
  154. getErrorMessage: function() { return ''; }
  155. });
  156. assertEquals(
  157. 'Unexpected call to fn1(string).\n' +
  158. 'Next expected call was to fn2(number)',
  159. msg);
  160. }
  161. // This tests that base Object functions which are not enumerable in IE can
  162. // be mocked correctly.
  163. function testBindNonEnumerableFunctions() {
  164. // Create Foo and override non enumerable functions.
  165. var Foo = function() {};
  166. Foo.prototype.constructor = function() {
  167. fail('real object should never be called');
  168. };
  169. Foo.prototype.hasOwnProperty = function() {
  170. fail('real object should never be called');
  171. };
  172. Foo.prototype.isPrototypeOf = function() {
  173. fail('real object should never be called');
  174. };
  175. Foo.prototype.propertyIsEnumerable = function() {
  176. fail('real object should never be called');
  177. };
  178. Foo.prototype.toLocaleString = function() {
  179. fail('real object should never be called');
  180. };
  181. Foo.prototype.toString = function() {
  182. fail('real object should never be called');
  183. };
  184. Foo.prototype.valueOf = function() {
  185. fail('real object should never be called');
  186. };
  187. // Create Mock and set $returns for toString.
  188. var mockControl = new goog.testing.MockControl();
  189. var mock = mockControl.createLooseMock(Foo);
  190. mock.constructor().$returns('constructor');
  191. mock.hasOwnProperty().$returns('hasOwnProperty');
  192. mock.isPrototypeOf().$returns('isPrototypeOf');
  193. mock.propertyIsEnumerable().$returns('propertyIsEnumerable');
  194. mock.toLocaleString().$returns('toLocaleString');
  195. mock.toString().$returns('toString');
  196. mock.valueOf().$returns('valueOf');
  197. // Execute and assert that the Mock is working correctly.
  198. mockControl.$replayAll();
  199. assertEquals('constructor', mock.constructor());
  200. assertEquals('hasOwnProperty', mock.hasOwnProperty());
  201. assertEquals('isPrototypeOf', mock.isPrototypeOf());
  202. assertEquals('propertyIsEnumerable', mock.propertyIsEnumerable());
  203. assertEquals('toLocaleString', mock.toLocaleString());
  204. assertEquals('toString', mock.toString());
  205. assertEquals('valueOf', mock.valueOf());
  206. mockControl.$verifyAll();
  207. }
  208. function testMockInheritedMethods() {
  209. var SubType = function() {};
  210. goog.inherits(SubType, RealObject);
  211. SubType.prototype.c = function() {
  212. fail('real object should never be called');
  213. };
  214. var mockControl = new goog.testing.MockControl();
  215. var mock = mockControl.createLooseMock(SubType);
  216. mock.a().$returns('a');
  217. mock.b().$returns('b');
  218. mock.c().$returns('c');
  219. // Execute and assert that the Mock is working correctly.
  220. mockControl.$replayAll();
  221. assertEquals('a', mock.a());
  222. assertEquals('b', mock.b());
  223. assertEquals('c', mock.c());
  224. mockControl.$verifyAll();
  225. }
  226. function testMockStaticMethods() {
  227. var SomeType = function() {};
  228. SomeType.staticMethod = function() {
  229. fail('real object should never be called');
  230. };
  231. var mockControl = new goog.testing.MockControl();
  232. var mock = mockControl.createLooseMock(
  233. SomeType, false /* opt_ignoreUnexpectedCalls */,
  234. true /* opt_mockStaticMethods */);
  235. mock.staticMethod().$returns('staticMethod');
  236. // Execute and assert that the Mock is working correctly.
  237. mockControl.$replayAll();
  238. assertEquals('staticMethod', mock.staticMethod());
  239. mockControl.$verifyAll();
  240. }
  241. function testMockEs6ClassMethods() {
  242. // Create an ES6 class via eval so we can bail out if it's a syntax error in
  243. // browsers that don't support ES6 classes.
  244. try {
  245. eval(
  246. 'var Foo = class {' +
  247. ' a() {' +
  248. ' fail(\'real object should never be called\');' +
  249. ' }' +
  250. '}');
  251. } catch (e) {
  252. if (e instanceof SyntaxError) {
  253. return;
  254. }
  255. }
  256. var mockControl = new goog.testing.MockControl();
  257. var mock = mockControl.createLooseMock(Foo);
  258. mock.a().$returns('a');
  259. // Execute and assert that the Mock is working correctly.
  260. mockControl.$replayAll();
  261. assertEquals('a', mock.a());
  262. mockControl.$verifyAll();
  263. }
  264. function testMockEs6ClassStaticMethods() {
  265. // Create an ES6 class via eval so we can bail out if it's a syntax error in
  266. // browsers that don't support ES6 classes.
  267. try {
  268. eval(
  269. 'var Foo = class {' +
  270. ' static a() {' +
  271. ' fail(\'real object should never be called\');' +
  272. ' }' +
  273. ' static apply() {' +
  274. ' fail(\'real object should never be called\');' +
  275. ' }' +
  276. '}');
  277. } catch (e) {
  278. if (e instanceof SyntaxError) {
  279. return;
  280. }
  281. }
  282. var mockControl = new goog.testing.MockControl();
  283. var mock = mockControl.createLooseMock(
  284. Foo, false /* opt_ignoreUnexpectedCalls */,
  285. true /* opt_mockStaticMethods */);
  286. mock.a().$returns('a');
  287. mock.apply().$returns('apply');
  288. // Execute and assert that the Mock is working correctly.
  289. mockControl.$replayAll();
  290. assertEquals('a', mock.a());
  291. assertEquals('apply', mock.apply());
  292. mockControl.$verifyAll();
  293. }