functionmock_test.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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.FunctionMockTest');
  15. goog.setTestOnly('goog.testing.FunctionMockTest');
  16. goog.require('goog.array');
  17. goog.require('goog.string');
  18. goog.require('goog.testing');
  19. goog.require('goog.testing.FunctionMock');
  20. goog.require('goog.testing.Mock');
  21. goog.require('goog.testing.ObjectPropertyString');
  22. goog.require('goog.testing.StrictMock');
  23. goog.require('goog.testing.asserts');
  24. goog.require('goog.testing.jsunit');
  25. goog.require('goog.testing.mockmatchers');
  26. // Global scope so we can tear it down safely
  27. var mockGlobal;
  28. function tearDown() {
  29. if (mockGlobal) {
  30. mockGlobal.$tearDown();
  31. }
  32. }
  33. //----- Tests for goog.testing.FunctionMock
  34. function testMockFunctionCallOrdering() {
  35. var doOneTest = function(mockFunction, success, expected_args, actual_args) {
  36. goog.array.forEach(expected_args, function(arg) { mockFunction(arg); });
  37. mockFunction.$replay();
  38. var callFunction = function() {
  39. goog.array.forEach(actual_args, function(arg) { mockFunction(arg); });
  40. mockFunction.$verify();
  41. };
  42. if (success) {
  43. callFunction();
  44. } else {
  45. assertThrowsJsUnitException(callFunction);
  46. }
  47. };
  48. var doTest = function(strict_ok, loose_ok, expected_args, actual_args) {
  49. doOneTest(
  50. goog.testing.createFunctionMock(), strict_ok, expected_args,
  51. actual_args);
  52. doOneTest(
  53. goog.testing.createFunctionMock('name'), strict_ok, expected_args,
  54. actual_args);
  55. doOneTest(
  56. goog.testing.createFunctionMock('name', goog.testing.Mock.STRICT),
  57. strict_ok, expected_args, actual_args);
  58. doOneTest(
  59. goog.testing.createFunctionMock('name', goog.testing.Mock.LOOSE),
  60. loose_ok, expected_args, actual_args);
  61. };
  62. doTest(true, true, [1, 2], [1, 2]);
  63. doTest(false, true, [1, 2], [2, 1]);
  64. doTest(false, false, [1, 2], [2, 2]);
  65. doTest(false, false, [1, 2], [1]);
  66. doTest(false, false, [1, 2], [1, 1]);
  67. doTest(false, false, [1, 2], [1]);
  68. }
  69. function testMocksFunctionWithNoArgs() {
  70. var mockFoo = goog.testing.createFunctionMock();
  71. mockFoo();
  72. mockFoo.$replay();
  73. mockFoo();
  74. mockFoo.$verify();
  75. }
  76. function testMocksFunctionWithOneArg() {
  77. var mockFoo = goog.testing.createFunctionMock();
  78. mockFoo('x');
  79. mockFoo.$replay();
  80. mockFoo('x');
  81. mockFoo.$verify();
  82. }
  83. function testMocksFunctionWithMultipleArgs() {
  84. var mockFoo = goog.testing.createFunctionMock();
  85. mockFoo('x', 'y');
  86. mockFoo.$replay();
  87. mockFoo('x', 'y');
  88. mockFoo.$verify();
  89. }
  90. function testFailsIfCalledWithIncorrectArgs() {
  91. var mockFoo = goog.testing.createFunctionMock();
  92. mockFoo();
  93. mockFoo.$replay();
  94. assertThrowsJsUnitException(function() { mockFoo('x'); });
  95. mockFoo.$reset();
  96. mockFoo('x');
  97. mockFoo.$replay();
  98. assertThrowsJsUnitException(function() { mockFoo(); });
  99. mockFoo.$reset();
  100. mockFoo('x');
  101. mockFoo.$replay();
  102. assertThrowsJsUnitException(function() { mockFoo('x', 'y'); });
  103. mockFoo.$reset();
  104. mockFoo('x', 'y');
  105. mockFoo.$replay();
  106. assertThrowsJsUnitException(function() { mockFoo('x'); });
  107. mockFoo.$reset();
  108. mockFoo('correct');
  109. mockFoo.$replay();
  110. assertThrowsJsUnitException(function() { mockFoo('wrong'); });
  111. mockFoo.$reset();
  112. mockFoo('correct', 'args');
  113. mockFoo.$replay();
  114. assertThrowsJsUnitException(function() { mockFoo('wrong', 'args'); });
  115. mockFoo.$reset();
  116. }
  117. function testMocksFunctionWithReturnValue() {
  118. var mockFoo = goog.testing.createFunctionMock();
  119. mockFoo().$returns('bar');
  120. mockFoo.$replay();
  121. assertEquals('bar', mockFoo());
  122. mockFoo.$verify();
  123. }
  124. function testFunctionMockWorksWhenPassedAsACallback() {
  125. var invoker = {
  126. register: function(callback) { this.callback = callback; },
  127. invoke: function(args) { return this.callback(args); }
  128. };
  129. var mockFunction = goog.testing.createFunctionMock();
  130. mockFunction('bar').$returns('baz');
  131. mockFunction.$replay();
  132. invoker.register(mockFunction);
  133. assertEquals('baz', invoker.invoke('bar'));
  134. mockFunction.$verify();
  135. }
  136. function testFunctionMockQuacksLikeAStrictMock() {
  137. var mockFunction = goog.testing.createFunctionMock();
  138. assertQuacksLike(mockFunction, goog.testing.StrictMock);
  139. }
  140. //----- Global functions for goog.testing.GlobalFunctionMock to mock
  141. function globalFoo() {
  142. return 'I am Spartacus!';
  143. }
  144. function globalBar(who, what) {
  145. return [who, 'is', what].join(' ');
  146. }
  147. //----- Tests for goog.testing.createGlobalFunctionMock
  148. function testMocksGlobalFunctionWithNoArgs() {
  149. mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
  150. mockGlobal().$returns('No, I am Spartacus!');
  151. mockGlobal.$replay();
  152. assertEquals('No, I am Spartacus!', globalFoo());
  153. mockGlobal.$verify();
  154. }
  155. function testMocksGlobalFunctionUsingGlobalName() {
  156. goog.testing.createGlobalFunctionMock('globalFoo');
  157. globalFoo().$returns('No, I am Spartacus!');
  158. globalFoo.$replay();
  159. assertEquals('No, I am Spartacus!', globalFoo());
  160. globalFoo.$verify();
  161. globalFoo.$tearDown();
  162. }
  163. function testMocksGlobalFunctionWithArgs() {
  164. var mockReturnValue = 'Noam is Chomsky!';
  165. mockGlobal = goog.testing.createGlobalFunctionMock('globalBar');
  166. mockGlobal('Noam', 'Spartacus').$returns(mockReturnValue);
  167. mockGlobal.$replay();
  168. assertEquals(mockReturnValue, globalBar('Noam', 'Spartacus'));
  169. mockGlobal.$verify();
  170. }
  171. function testGlobalFunctionMockFailsWithIncorrectArgs() {
  172. mockGlobal = goog.testing.createGlobalFunctionMock('globalBar');
  173. mockGlobal('a', 'b');
  174. mockGlobal.$replay();
  175. assertThrowsJsUnitException(function() { globalBar('b', 'a'); });
  176. }
  177. function testGlobalFunctionMockQuacksLikeAFunctionMock() {
  178. mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
  179. assertQuacksLike(mockGlobal, goog.testing.FunctionMock);
  180. }
  181. function testMockedFunctionsAvailableInGlobalAndGoogGlobalAndWindowScope() {
  182. mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
  183. // we expect this call 3 times through global, goog.global and window scope
  184. mockGlobal().$times(3);
  185. mockGlobal.$replay();
  186. goog.global.globalFoo();
  187. window.globalFoo();
  188. globalFoo();
  189. mockGlobal.$verify();
  190. }
  191. function testTearDownRestoresOriginalGlobalFunction() {
  192. mockGlobal = goog.testing.createGlobalFunctionMock('globalFoo');
  193. mockGlobal().$returns('No, I am Spartacus!');
  194. mockGlobal.$replay();
  195. assertEquals('No, I am Spartacus!', globalFoo());
  196. mockGlobal.$tearDown();
  197. assertEquals('I am Spartacus!', globalFoo());
  198. mockGlobal.$verify();
  199. }
  200. function testTearDownHandlesMultipleMocking() {
  201. var mock1 = goog.testing.createGlobalFunctionMock('globalFoo');
  202. var mock2 = goog.testing.createGlobalFunctionMock('globalFoo');
  203. var mock3 = goog.testing.createGlobalFunctionMock('globalFoo');
  204. mock1().$returns('No, I am Spartacus 1!');
  205. mock2().$returns('No, I am Spartacus 2!');
  206. mock3().$returns('No, I am Spartacus 3!');
  207. mock1.$replay();
  208. mock2.$replay();
  209. mock3.$replay();
  210. assertEquals('No, I am Spartacus 3!', globalFoo());
  211. mock3.$tearDown();
  212. assertEquals('No, I am Spartacus 2!', globalFoo());
  213. mock2.$tearDown();
  214. assertEquals('No, I am Spartacus 1!', globalFoo());
  215. mock1.$tearDown();
  216. assertEquals('I am Spartacus!', globalFoo());
  217. }
  218. function testGlobalFunctionMockCallOrdering() {
  219. var mock = goog.testing.createGlobalFunctionMock('globalFoo');
  220. mock(1);
  221. mock(2);
  222. mock.$replay();
  223. assertThrowsJsUnitException(function() { globalFoo(2); });
  224. mock.$tearDown();
  225. mock = goog.testing.createGlobalFunctionMock(
  226. 'globalFoo', goog.testing.Mock.STRICT);
  227. mock(1);
  228. mock(2);
  229. mock.$replay();
  230. globalFoo(1);
  231. globalFoo(2);
  232. mock.$verify();
  233. mock.$tearDown();
  234. mock = goog.testing.createGlobalFunctionMock(
  235. 'globalFoo', goog.testing.Mock.STRICT);
  236. mock(1);
  237. mock(2);
  238. mock.$replay();
  239. assertThrowsJsUnitException(function() { globalFoo(2); });
  240. mock.$tearDown();
  241. mock = goog.testing.createGlobalFunctionMock(
  242. 'globalFoo', goog.testing.Mock.LOOSE);
  243. mock(1);
  244. mock(2);
  245. mock.$replay();
  246. globalFoo(2);
  247. globalFoo(1);
  248. mock.$verify();
  249. mock.$tearDown();
  250. }
  251. //----- Functions for goog.testing.MethodMock to mock
  252. var mynamespace = {};
  253. mynamespace.myMethod = function() {
  254. return 'I should be mocked.';
  255. };
  256. function testMocksMethod() {
  257. mockMethod = goog.testing.createMethodMock(mynamespace, 'myMethod');
  258. mockMethod().$returns('I have been mocked!');
  259. mockMethod.$replay();
  260. assertEquals('I have been mocked!', mockMethod());
  261. mockMethod.$verify();
  262. }
  263. function testMocksMethodInNamespace() {
  264. goog.testing.createMethodMock(mynamespace, 'myMethod');
  265. mynamespace.myMethod().$returns('I have been mocked!');
  266. mynamespace.myMethod.$replay();
  267. assertEquals('I have been mocked!', mynamespace.myMethod());
  268. mynamespace.myMethod.$verify();
  269. mynamespace.myMethod.$tearDown();
  270. }
  271. function testMethodMockCanOnlyMockExistingMethods() {
  272. assertThrows(function() {
  273. goog.testing.createMethodMock(mynamespace, 'doesNotExist');
  274. });
  275. }
  276. function testMethodMockCallOrdering() {
  277. goog.testing.createMethodMock(mynamespace, 'myMethod');
  278. mynamespace.myMethod(1);
  279. mynamespace.myMethod(2);
  280. mynamespace.myMethod.$replay();
  281. assertThrowsJsUnitException(function() { mynamespace.myMethod(2); });
  282. mynamespace.myMethod.$tearDown();
  283. goog.testing.createMethodMock(
  284. mynamespace, 'myMethod', goog.testing.Mock.STRICT);
  285. mynamespace.myMethod(1);
  286. mynamespace.myMethod(2);
  287. mynamespace.myMethod.$replay();
  288. mynamespace.myMethod(1);
  289. mynamespace.myMethod(2);
  290. mynamespace.myMethod.$verify();
  291. mynamespace.myMethod.$tearDown();
  292. goog.testing.createMethodMock(
  293. mynamespace, 'myMethod', goog.testing.Mock.STRICT);
  294. mynamespace.myMethod(1);
  295. mynamespace.myMethod(2);
  296. mynamespace.myMethod.$replay();
  297. assertThrowsJsUnitException(function() { mynamespace.myMethod(2); });
  298. mynamespace.myMethod.$tearDown();
  299. goog.testing.createMethodMock(
  300. mynamespace, 'myMethod', goog.testing.Mock.LOOSE);
  301. mynamespace.myMethod(1);
  302. mynamespace.myMethod(2);
  303. mynamespace.myMethod.$replay();
  304. mynamespace.myMethod(2);
  305. mynamespace.myMethod(1);
  306. mynamespace.myMethod.$verify();
  307. mynamespace.myMethod.$tearDown();
  308. }
  309. function testMocksMethodFromObjectPropertyString() {
  310. mockMethod = goog.testing.MethodMock.fromObjectPropertyString(
  311. new goog.testing.ObjectPropertyString(mynamespace, 'myMethod'));
  312. mockMethod().$returns('I have been mocked!');
  313. mockMethod.$replay();
  314. assertEquals('I have been mocked!', mynamespace.myMethod());
  315. mockMethod.$verify();
  316. }
  317. //----- Functions for goog.testing.createConstructorMock to mock
  318. var constructornamespace = {};
  319. constructornamespace.MyConstructor = function() {};
  320. constructornamespace.MyConstructor.prototype.myMethod = function() {
  321. return 'I should be mocked.';
  322. };
  323. constructornamespace.MyConstructorWithArgument = function(argument) {
  324. this.argument_ = argument;
  325. };
  326. constructornamespace.MyConstructorWithArgument.prototype.myMethod = function() {
  327. return this.argument_;
  328. };
  329. constructornamespace.MyConstructorWithClassMembers = function() {};
  330. constructornamespace.MyConstructorWithClassMembers.CONSTANT = 42;
  331. constructornamespace.MyConstructorWithClassMembers.classMethod = function() {
  332. return 'class method return value';
  333. };
  334. function testConstructorMock() {
  335. var mockObject =
  336. new goog.testing.StrictMock(constructornamespace.MyConstructor);
  337. var mockConstructor =
  338. goog.testing.createConstructorMock(constructornamespace, 'MyConstructor');
  339. mockConstructor().$returns(mockObject);
  340. mockObject.myMethod().$returns('I have been mocked!');
  341. mockConstructor.$replay();
  342. mockObject.$replay();
  343. assertEquals(
  344. 'I have been mocked!',
  345. new constructornamespace.MyConstructor().myMethod());
  346. mockConstructor.$verify();
  347. mockObject.$verify();
  348. mockConstructor.$tearDown();
  349. }
  350. function testConstructorMockWithArgument() {
  351. var mockObject = new goog.testing.StrictMock(
  352. constructornamespace.MyConstructorWithArgument);
  353. var mockConstructor = goog.testing.createConstructorMock(
  354. constructornamespace, 'MyConstructorWithArgument');
  355. mockConstructor(goog.testing.mockmatchers.isString).$returns(mockObject);
  356. mockObject.myMethod().$returns('I have been mocked!');
  357. mockConstructor.$replay();
  358. mockObject.$replay();
  359. assertEquals(
  360. 'I have been mocked!',
  361. new constructornamespace.MyConstructorWithArgument('I should be mocked.')
  362. .myMethod());
  363. mockConstructor.$verify();
  364. mockObject.$verify();
  365. mockConstructor.$tearDown();
  366. }
  367. /**
  368. * Test that class members are copied to the mock constructor.
  369. */
  370. function testConstructorMockWithClassMembers() {
  371. var mockConstructor = goog.testing.createConstructorMock(
  372. constructornamespace, 'MyConstructorWithClassMembers');
  373. assertEquals(42, constructornamespace.MyConstructorWithClassMembers.CONSTANT);
  374. assertEquals(
  375. 'class method return value',
  376. constructornamespace.MyConstructorWithClassMembers.classMethod());
  377. mockConstructor.$tearDown();
  378. }
  379. function testConstructorMockCallOrdering() {
  380. var instance = {};
  381. goog.testing.createConstructorMock(
  382. constructornamespace, 'MyConstructorWithArgument');
  383. constructornamespace.MyConstructorWithArgument(1).$returns(instance);
  384. constructornamespace.MyConstructorWithArgument(2).$returns(instance);
  385. constructornamespace.MyConstructorWithArgument.$replay();
  386. assertThrowsJsUnitException(function() {
  387. new constructornamespace.MyConstructorWithArgument(2);
  388. });
  389. constructornamespace.MyConstructorWithArgument.$tearDown();
  390. goog.testing.createConstructorMock(
  391. constructornamespace, 'MyConstructorWithArgument',
  392. goog.testing.Mock.STRICT);
  393. constructornamespace.MyConstructorWithArgument(1).$returns(instance);
  394. constructornamespace.MyConstructorWithArgument(2).$returns(instance);
  395. constructornamespace.MyConstructorWithArgument.$replay();
  396. new constructornamespace.MyConstructorWithArgument(1);
  397. new constructornamespace.MyConstructorWithArgument(2);
  398. constructornamespace.MyConstructorWithArgument.$verify();
  399. constructornamespace.MyConstructorWithArgument.$tearDown();
  400. goog.testing.createConstructorMock(
  401. constructornamespace, 'MyConstructorWithArgument',
  402. goog.testing.Mock.STRICT);
  403. constructornamespace.MyConstructorWithArgument(1).$returns(instance);
  404. constructornamespace.MyConstructorWithArgument(2).$returns(instance);
  405. constructornamespace.MyConstructorWithArgument.$replay();
  406. assertThrowsJsUnitException(function() {
  407. new constructornamespace.MyConstructorWithArgument(2);
  408. });
  409. constructornamespace.MyConstructorWithArgument.$tearDown();
  410. goog.testing.createConstructorMock(
  411. constructornamespace, 'MyConstructorWithArgument',
  412. goog.testing.Mock.LOOSE);
  413. constructornamespace.MyConstructorWithArgument(1).$returns(instance);
  414. constructornamespace.MyConstructorWithArgument(2).$returns(instance);
  415. constructornamespace.MyConstructorWithArgument.$replay();
  416. new constructornamespace.MyConstructorWithArgument(2);
  417. new constructornamespace.MyConstructorWithArgument(1);
  418. constructornamespace.MyConstructorWithArgument.$verify();
  419. constructornamespace.MyConstructorWithArgument.$tearDown();
  420. }
  421. //----- Helper assertions
  422. function assertQuacksLike(obj, target) {
  423. for (meth in target.prototype) {
  424. if (!goog.string.endsWith(meth, '_')) {
  425. assertNotUndefined('Should have implemented ' + meth + '()', obj[meth]);
  426. }
  427. }
  428. }