loosemock_test.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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.LooseMockTest');
  15. goog.setTestOnly('goog.testing.LooseMockTest');
  16. goog.require('goog.testing.LooseMock');
  17. goog.require('goog.testing.PropertyReplacer');
  18. goog.require('goog.testing.jsunit');
  19. goog.require('goog.testing.mockmatchers');
  20. // The object that we will be mocking
  21. var RealObject = function() {};
  22. RealObject.prototype.a = function() {
  23. fail('real object should never be called');
  24. };
  25. RealObject.prototype.b = function() {
  26. fail('real object should never be called');
  27. };
  28. var mock;
  29. var stubs;
  30. function setUp() {
  31. var obj = new RealObject();
  32. mock = new goog.testing.LooseMock(obj);
  33. stubs = new goog.testing.PropertyReplacer();
  34. }
  35. function tearDown() {
  36. stubs.reset();
  37. }
  38. /*
  39. * Calling this method evades the logTestFailure in
  40. * goog.testing.Mock.prototype.$recordAndThrow, so it doesn't look like the
  41. * test failed.
  42. */
  43. function silenceFailureLogging() {
  44. if (goog.global['G_testRunner']) {
  45. stubs.set(goog.global['G_testRunner'], 'logTestFailure', goog.nullFunction);
  46. }
  47. }
  48. function unsilenceFailureLogging() {
  49. stubs.reset();
  50. }
  51. /**
  52. * Version of assertThrows that doesn't log the exception generated by the
  53. * mocks under test.
  54. * TODO: would be nice to check that a particular substring is in the thrown
  55. * message so we know it's not something dumb like a syntax error
  56. */
  57. function assertThrowsQuiet(var_args) {
  58. silenceFailureLogging();
  59. assertThrowsJsUnitException.apply(null, arguments);
  60. unsilenceFailureLogging();
  61. }
  62. // Most of the basic functionality is tested in strictmock_test; these tests
  63. // cover the cases where loose mocks are different from strict mocks
  64. function testSimpleExpectations() {
  65. mock.a(5);
  66. mock.b();
  67. mock.$replay();
  68. mock.a(5);
  69. mock.b();
  70. mock.$verify();
  71. mock.$reset();
  72. mock.a();
  73. mock.b();
  74. mock.$replay();
  75. mock.b();
  76. mock.a();
  77. mock.$verify();
  78. mock.$reset();
  79. mock.a(5).$times(2);
  80. mock.a(5);
  81. mock.a(2);
  82. mock.$replay();
  83. mock.a(5);
  84. mock.a(5);
  85. mock.a(5);
  86. mock.a(2);
  87. mock.$verify();
  88. }
  89. function testMultipleExpectations() {
  90. mock.a().$returns(1);
  91. mock.a().$returns(2);
  92. mock.$replay();
  93. assertEquals(1, mock.a());
  94. assertEquals(2, mock.a());
  95. mock.$verify();
  96. }
  97. function testMultipleExpectationArgs() {
  98. mock.a('asdf').$anyTimes();
  99. mock.a('qwer').$anyTimes();
  100. mock.b().$times(3);
  101. mock.$replay();
  102. mock.a('asdf');
  103. mock.b();
  104. mock.a('asdf');
  105. mock.a('qwer');
  106. mock.b();
  107. mock.a('qwer');
  108. mock.b();
  109. mock.$verify();
  110. mock.$reset();
  111. mock.a('asdf').$anyTimes();
  112. mock.a('qwer').$anyTimes();
  113. mock.$replay();
  114. mock.a('asdf');
  115. mock.a('qwer');
  116. goog.bind(mock.a, mock, 'asdf');
  117. goog.bind(mock.$verify, mock);
  118. }
  119. function testSameMethodOutOfOrder() {
  120. mock.a('foo').$returns(1);
  121. mock.a('bar').$returns(2);
  122. mock.$replay();
  123. assertEquals(2, mock.a('bar'));
  124. assertEquals(1, mock.a('foo'));
  125. }
  126. function testSameMethodDifferentReturnValues() {
  127. mock.a('foo').$returns(1).$times(2);
  128. mock.a('foo').$returns(3);
  129. mock.a('bar').$returns(2);
  130. mock.$replay();
  131. assertEquals(1, mock.a('foo'));
  132. assertEquals(2, mock.a('bar'));
  133. assertEquals(1, mock.a('foo'));
  134. assertEquals(3, mock.a('foo'));
  135. assertThrowsQuiet(function() {
  136. mock.a('foo');
  137. mock.$verify();
  138. });
  139. }
  140. function testSameMethodBrokenExpectations() {
  141. // This is a weird corner case.
  142. // No way to ever make this verify no matter what you call after replaying,
  143. // because the second expectation of mock.a('foo') will be masked by
  144. // the first expectation that can be called any number of times, and so we
  145. // can never satisfy that second expectation.
  146. mock.a('foo').$returns(1).$anyTimes();
  147. mock.a('bar').$returns(2);
  148. mock.a('foo').$returns(3);
  149. // LooseMock can detect this case and fail on $replay.
  150. assertThrowsQuiet(goog.bind(mock.$replay, mock));
  151. mock.$reset();
  152. // This is a variant of the corner case above, but it's harder to determine
  153. // that the expectation to mock.a('bar') can never be satisfied. So we don't
  154. // fail on $replay, but we do fail on $verify.
  155. mock.a(goog.testing.mockmatchers.isString).$returns(1).$anyTimes();
  156. mock.a('bar').$returns(2);
  157. mock.$replay();
  158. assertEquals(1, mock.a('foo'));
  159. assertEquals(1, mock.a('bar'));
  160. assertThrowsQuiet(goog.bind(mock.$verify, mock));
  161. }
  162. function testSameMethodMultipleAnyTimes() {
  163. mock.a('foo').$returns(1).$anyTimes();
  164. mock.a('foo').$returns(2).$anyTimes();
  165. mock.$replay();
  166. assertEquals(1, mock.a('foo'));
  167. assertEquals(1, mock.a('foo'));
  168. assertEquals(1, mock.a('foo'));
  169. // Note we'll never return 2 but that's ok.
  170. mock.$verify();
  171. }
  172. function testFailingFast() {
  173. mock.a().$anyTimes();
  174. mock.$replay();
  175. mock.a();
  176. mock.a();
  177. assertThrowsQuiet(goog.bind(mock.b, mock));
  178. mock.$reset();
  179. // too many
  180. mock.a();
  181. mock.b();
  182. mock.$replay();
  183. mock.a();
  184. mock.b();
  185. var message;
  186. silenceFailureLogging();
  187. try {
  188. mock.a();
  189. } catch (e) {
  190. message = e.message;
  191. }
  192. unsilenceFailureLogging();
  193. assertTrue('No exception thrown on unexpected call', goog.isDef(message));
  194. assertContains('Too many calls to a', message);
  195. }
  196. function testTimes() {
  197. mock.a().$times(3);
  198. mock.b().$times(2);
  199. mock.$replay();
  200. mock.a();
  201. mock.b();
  202. mock.b();
  203. mock.a();
  204. mock.a();
  205. mock.$verify();
  206. }
  207. function testFailingSlow() {
  208. // not enough
  209. mock.a().$times(3);
  210. mock.$replay();
  211. mock.a();
  212. mock.a();
  213. assertThrowsQuiet(goog.bind(mock.$verify, mock));
  214. mock.$reset();
  215. // not enough, interleaved order
  216. mock.a().$times(3);
  217. mock.b().$times(3);
  218. mock.$replay();
  219. mock.a();
  220. mock.b();
  221. mock.a();
  222. mock.b();
  223. assertThrowsQuiet(goog.bind(mock.$verify, mock));
  224. mock.$reset();
  225. // bad args
  226. mock.a('asdf').$anyTimes();
  227. mock.$replay();
  228. mock.a('asdf');
  229. assertThrowsQuiet(goog.bind(mock.a, mock, 'qwert'));
  230. assertThrowsQuiet(goog.bind(mock.$verify, mock));
  231. }
  232. function testArgsAndReturns() {
  233. mock.a('asdf').$atLeastOnce().$returns(5);
  234. mock.b('qwer').$times(2).$returns(3);
  235. mock.$replay();
  236. assertEquals(5, mock.a('asdf'));
  237. assertEquals(3, mock.b('qwer'));
  238. assertEquals(5, mock.a('asdf'));
  239. assertEquals(5, mock.a('asdf'));
  240. assertEquals(3, mock.b('qwer'));
  241. mock.$verify();
  242. }
  243. function testThrows() {
  244. mock.a().$throws('exception!');
  245. mock.$replay();
  246. assertThrows(goog.bind(mock.a, mock));
  247. mock.$verify();
  248. }
  249. function testDoes() {
  250. mock.a(1, 2).$does(function(a, b) { return a + b; });
  251. mock.$replay();
  252. assertEquals('Mock should call the function', 3, mock.a(1, 2));
  253. mock.$verify();
  254. }
  255. function testIgnoresExtraCalls() {
  256. mock = new goog.testing.LooseMock(RealObject, true);
  257. mock.a();
  258. mock.$replay();
  259. mock.a();
  260. mock.b(); // doesn't throw
  261. mock.$verify();
  262. }
  263. function testSkipAnyTimes() {
  264. mock = new goog.testing.LooseMock(RealObject);
  265. mock.a(1).$anyTimes();
  266. mock.a(2).$anyTimes();
  267. mock.a(3).$anyTimes();
  268. mock.$replay();
  269. mock.a(1);
  270. mock.a(3);
  271. mock.$verify();
  272. }
  273. function testErrorMessageForBadArgs() {
  274. mock.a();
  275. mock.$anyTimes();
  276. mock.$replay();
  277. var message;
  278. silenceFailureLogging();
  279. try {
  280. mock.a('a');
  281. } catch (e) {
  282. message = e.message;
  283. }
  284. unsilenceFailureLogging();
  285. assertTrue('No exception thrown on verify', goog.isDef(message));
  286. assertContains('Bad arguments to a()', message);
  287. }