问题
I'm testing an asynchronous piece of code with something that looks like this:
randomService.doSomething().then(function() {
console.log('I completed the operation!');
});
Surprisingly (to me) I've found that it only succeeds (ie console.log output is shown) when wrapped inside jasmine's runs
function, like so:
var isDone = false;
runs(function() {
randomService.doSomething().then(function(data) {
console.log('I completed the operation!');
isDone = true;
});
});
waitsFor(function() {
return isDone;
}, 'Operation should be completed', 1000);
As I understood it, I thought waitsFor
was only to delay the code, in other words I would use it if I had more code that I had to delay until after the asynchronous call completed - in other words, I would have thought that there'd be no reason for me to use runs
and waitsFor
since there's nothing that comes after this bit of code, right? That's the impression I got from reading this question: What do jasmine runs and waitsFor actually do? but obviously I've gotten myself mixed up at some point.
Does anyone have any thoughts on this?
EDIT: Here is a Plunker with far more detail of the problem: http://plnkr.co/edit/3qnuj5N9Thb2UdgoxYaD?p=preview
Note how the first test always passes, and the second test fails as it should. Also, I'm sure I should have mentioned this before, but this is using angularJS, and Jasmine 1.3.
回答1:
I think I found the issue. Here's the article: http://blogs.lessthandot.com/index.php/webdev/uidevelopment/javascript/testing-asynchronous-javascript-w-jasmine/
Essentially it's necessary because Jasmine doesn't wait for the asynchronous calls to finish before it completes a test. According to the article, if a call takes long enough and there are more tests later, an expect
statement in an asynchronous callback in a previous test could finally execute in a different test entirely, after the original test completed.
Using runs
and waitsFor
solve the problem because they force jasmine to wait for the waitsFor
to finish before proceeding to the next test; This is a moot point however because evidently Jasmine 2.0 addresses asynchronous testing in a better way than 1.3, obsoleting runs
and waitsFor
.
回答2:
That's just how Jasmine works. The question you linked has an answer with a decent explanation:
Essentially, the runs() and waitFor() functions stuff an array with their provided functions. The array is then processed by jamine wherein the functions are invoked sequentially. Those functions registered by runs() are expected to perform actual work while those registered by waitFor() are expected to be 'latch' functions and will be polled (invoked) every 10ms until they return true or the optional registered timeout period expires. If the timeout period expires an error is reported using the optional registered error message; otherwise, the process continues with the next function in the array.
To sum it up, each waitsFor
call must have a corresponding runs
call. They work together. Calling waitsFor
without a runs
call somewhere before it does not make sense.
My revised plunker (see comments on this answer): http://plnkr.co/edit/9eL9d9uERre4Q17lWQmw
As you can see, I added $rootScope.$apply();
to the the timeout function you were testing with. This makes the console.log
inside the promise callback run. HOWEVER it only runs if you ignore the other test with an xit
, AND the expect
after the console.log
does not seem to be recognized as a Jasmine test (though it certainly must run, because the console.log
does).
Very weird - I don't really understand why this is happening, but I think it has something to do with how Jasmine works behind the scenes, how it registers tests and whatnot. My understanding at this point is if you have an expect
inside an async callback, Jasmine won't "recognize" it as a part of the test suite unless the initial async call was made inside a runs
.
As for why this is, I don't know. I don't think it's worth trying to understand - I would just use runs
and waitsFor
and not worry about it, but that's just me. You can always dig through the source if you're feeling masochistic. Sorry I couldn't be of more help.
来源:https://stackoverflow.com/questions/24619664/why-is-using-jasmines-runs-and-waitfor-function-necessary