14 ms·
I'm back in Java-land these days, which is culturally very pro-unit testing. After getting exposed to it again for a few months again I've come to side with the
by revscat 13y ago
I'm back in Java-land these days, which is culturally very pro-unit testing. After getting exposed to it again for a few months again I've come to side with the author here. I've never really been comfortable with the amount of time certain people dedicate to unit testing, especially the TDD crowd, but in my hiatus something has arisen in popularity which has made it all the worse: mockito.
Prior to mockito, unit testing was (more or less) limited to testing that your methods behaved as expected, and would occasionally expose NullPointerExceptions or other exceptional conditions. Dependent objects were either simplified or simply ignored. With the rise of mock object frameworks, however, your tests specifically say "this method on this mock will be called X number of times, with this result". Mind you, this is all happening in the context of another method call. So, for example, if you were testing the method "calculateDueDate", and that method took a DateTime object, your test might look like this:
@Before
public void setup() {
MyClass myClass = new MyClass();
DateTime mockDateTime = mock(DateTime.class);
}
@Test
public void specificDueDateShouldBeTenDaysFromNow() {
DateTime result = myClass.calculateDueDate(mockDateTime);
verify(mockDateTime, times(2)).getHour(); // contrived
}
The problem with this is that the tests become obstacles in the way of refactoring the code. Should you decide that you don't want to use the DateTime library any longer you will have to not just change the code which is using it but the tests as well. Or what if, going back to the example above, you decided not to use the getHour() method any more? Every test referencing that will have to be changed. And changing those tests is very likely to be more involved than changing the code under test, because there frequently are more tests than code. This has a negative impact on the design of the application. Because companies rarely dedicate resources to making existing software better purely for its own sake, you tend to have to do what you can when you can. This means your time is limited to make that refactor, or upgrade that library, or do whatevever change it is that needs to be done. Unit tests, especially those that use mocks, can get in the way of this to such an extent as to make such efforts impossible.
I think testing is important. I do not, however, share the belief that is the sole, or even primary, determinant of code quality. In fact, an over reliance on unit testing can easily be a net negative. Should unit tests be thrown out? No. Baby with the bathwater and all that. But they should not be viewed as a silver bullet, either. They're not. They can help, but they can hurt.
- tel 13y agoThat just sounds like a terrible functional spec. If it's a core part of the behavior that some mocked object is called 11 times then so be it, and so mock it. You're not introducing brittleness via your tests—you're introducing it because your functional spec is highly complex.
- e28eta 13y agoI agree that this usage of mocks is detrimental. I think the only verification that should be done with mocks (the verify method) is that important collaborators have been called. Things that run off and mutate some global state, or perform an action. Stubs are useful for controlling the execution state of the method under test. You could stub DateTime such that it was midnight in one test, and noon in another, if the behavior of the function relied on that. It does introduce a dependency that has to be changed along with the code, but is often helpful. I do agree with the author that there's an art to testing appropriately. You could mechanically write testing code for every line of code under test (if statement with single condition? Two tests to verify each path is taken!), which leads to your app being coded twice: once in code and once (or more) in the tests.
- revscat 13y ago> It does introduce a dependency that has to be changed along with the code, but is often helpful. And that's the rub. Mocks are useful. They help you write tests that are more robust, without having to resort to massive and complex @Befores. At the same time, though, they have an effect that is more negative than positive on the ability to change the code under test.
- narrator 13y agoThe only thing mocks are good for IMHO is when the real code takes too long to run. Actually testing that a function is called twice is not what you're testing and this level of coupling to the supposedly encapsulated behavior of the method is ridiculous. The method is not called "callMethodInClassFooTwice()" it's called calculateInterestRate() or whatever and as long as it does that right that's all that's important.