问题
One can write unit tests either the classicist or the mockist way as per http://martinfowler.com/articles/mocksArentStubs.html
Will writing both classist and mockist unit tests for a single method increase robustness of the code since both state and behaviour is tested?
My colleagues seem to just be mocking all the way, and as they're the "example", it is assumed that I will be mocking as well unless I have a good reason not to. (I'm new to unit testing). However, I feel that testing just the mockist way assumes the correctness of the implementation of untested private methods, and that's why I want classist tests as well (to test the private methods indirectly).
Or is it a waste of time?
回答1:
Private methods are just internal workings of a class. To put it another way, if you fully test the public methods then the private methods but be, by definition, doing exactly what they need to do as only the public behaviour is important.
I have two thoughts regarding 'state'.
1) If the state is internal (private) then it is an implementation of how behaviour is achieved. It is an internal 'secret'. If it is important then test the resulting behaviour.
2) If the state is public ... no issue.
I would go for mocking.
回答2:
Testing with Mocks does test private methods indirectly as well - any private method should have some public method up in the call stack. If you've acheived 100% code coverage of your public methods, all your private methods will get called.
As I recall from Fowler article, the difference is that mockist test the inner working of the class - they verify that your class calls other classes API as they expected to. It makes sense where the functionality of your class will suffer if you'll fail to use it correctely - e.g. if you don't write some data to database, or even worse: write the wrong data.
回答3:
Either mocks or stubs are generally not used to test private members, as these members are the very core of encapsulation and nobody shall rely on even existence of the private members in newer versions of an assembly. If you do need to unit-test private members consider reading How do you unit test private methods?.
A good reason to use stubs instead of mocks is obvious, i.e. when you need to verify the state of the object after particular action, if it fits the task you shall use them. Some people wrongly believe that mocking is a new generation of unit-testing and one shall not use outdated stubs. Where in fact, you can effectively use both techniques separately or in a combination.
回答4:
Yes. Using both strategies will ensure robustness of the code under test as you are testing the contract of the code between it's dependencies (mockist) and simulating the functionality of the production environment (state). By blending the two approaches you guarantee a balanced testing approach.
Note however that state based testing typically requires more overhead because you must set up and configure the environment for all the components that are concerned with the subject under test. This usually leads to brittle tests. Having a small portion of state based tests to mockist tests should suffice.
Using a mockist strategy promotes the Single Responsibility Principle, where each class has a finite set of responsibilities and depends on other classes for their responsibilities. In my experience, if the responsibilities between objects is poorly defined you will find yourself falling into state based testing, which suggests an encapsulation or abstraction problem.
回答5:
Will writing both classist and mockist unit tests for a single method increase robustness of the code since both state and behaviour is tested?
No. Testing a thing twice is Duplication.
Last time I checked, the approaches are not exclusive.. rather they are complementary. Based on the specifics of the individual test, you can choose the best approach.
- if you're dealing with the behavior of a class, where the dependencies are test-friendly use state-based tests.
- if you're dealing with a dependency on the filesystem / network, there is no option but to check interaction. Did I call SaveFile()? However this is not a free-pass to introduce interfaces between any 2 classes that call each other. Although this is a common criticism of the 'mockist' approach, the truth is that the true 'mockists' work very hard at discovering the minimal robust roles/interfaces and specifying the absolute minimum (expectations). The cargo-cultists define interfaces between everything claiming it as the right way; the roles are unstable change-magnets, the tests have too many expectations leading to brittle tests. Each time there is an interface change, there is a lot of test maintenance.
来源:https://stackoverflow.com/questions/8666495/is-there-any-advantage-to-writing-both-classist-and-mockist-unit-tests-for-a-sin