开发者

Behavior vs. State Based Testing

I know this question is part of a bit of a religious war, but I have the following situation: I have an object, Responder that calls a method on object Updaterin response to different events. I recently separated the testing in this way: state-based tests for the Updater method itself, and behavior-based tests for the Responder that calls it. That is, I mock the 开发者_高级运维Updater in the Responder tests, just to ensure that it is called.

Should I still be testing the state of the objects that are supposed to be updated in the Responder tests and not mocking the Updater? I like what I have done because it requires less setup and seems to better isolate the tests. However, this seems to tie the implementation and expected behavior of Responder to Updater. Is that too brittle? This is a simplified example.


If I did understand your question correctly you really need at least two levels of testing:

  1. Unit tests, where you are trying to test only one class and mock all the dependencies (so in your case Updater needs to be mocked here). These tests help you develop the code (especially if you are using TDD), make sure the class behaves as designed and even document how this class is meant to behave. Pretty much every class should have unit tests. However, as you noticed even if you have 100% test coverage you have no guarantee that your program works or even starts up!

  2. Acceptance, integration and end-to-end tests - these tests cover either the whole application or big modules and test that everything works together. In general you don't use mocks at this level (you might stub a whole module/web service though, depending on the context). These tests don't have to test every single implementation detail (and shouldn't), because this is done by unit tests. They make sure that everything is correctly wired and working together. In your case you wouldn't mock Updater here.

So to sum up I think you really need to do both to have your application properly tested.


I guess it depends on what/how you are trying to test.

If you don't have any dependency in the Updater class, there is no other way than to test it's state after calling the method under test. If there is some dependency, you could test it's behavior as to what it should do (calling other methods on other classes)

The other way around could also be true for the Responder class. You could test it's state or you can test it's behavior as you did just now. Testing it's state you will likely use the real implementation of the Updater and not mock it, or use a stub in it's place that does just the minimum.

When mostly testing behavior and mocking a lot of stuff, it would be even more necessary to have acceptance (regression/integration/end-to-end) tests to back up your unit tests, just like Grzenio mentions. (It seems he is a "mockist" (behavior) tester)

When doing state based testing mostly, you use more real implementations and their interaction and the need to back those up is less relevant. But this is by no means a way to discard them entirely, it's just that you already have some regression/integration in your tests.

I think you shouldn't split the tests up too much as that might make it easier for things to fall in between the cracks.

Disclaimer: I am not a tdd guru and I don't advocate one over the other. Good info about classic vs behavior can be found on the net. Martin Fowler hasa good starting point on the subject: Mocks Aren't Stubs

I am currently reading Growing Object Oriented Software, Guided by Tests and am leaning towards the mockist side of the fence. But I think there is a small grey area on both sides.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜