3 ms·
Adding interfaces whose only purpose is unit tests is not keeping the code simpler. Using a test library that automatically generates mocks for unit testing is
by MockObject 7y ago
Adding interfaces whose only purpose is unit tests is not keeping the code simpler. Using a test library that automatically generates mocks for unit testing is what keeps the code simpler.
- CraigJPerry 7y ago>> automatically generates mocks for unit testing is what keeps the code simpler You're possibly confusing easy with simple but adding a versioned library of some thousands of lines of code to a project is in no objective way simpler than adding a small test double which you wrote.
- MockObject 7y agoYes, it is, in the only objective way that people actually care about: the size and simplicity of the source code. (What people don't care about is the size of libraries that are scoped for the test context only, and don't even impact artifact size at all.) Also, a Mockito mock is simpler in usage than a hand-written and normally instantiated test double.
- CraigJPerry 7y agoRipping off the classic talk by Rich Hickey: Simple - composed of a single element; not compound Complex - consisting of many different and connected parts Easy - achieved without great effort; presenting few difficulties. This is not as easy but is simple. It is explicit, fundamental Java. public void allocationOnlyPossibleWhenOpen() { LocalDateTime expected = LocalDateTime.now(); TimeAllocator sut = new TimeAllocator(new Clock() { public LocalDateTime getTime() { return expected; } }); sut.setOpen(false); assertThat(sut.allocate()).isNull(); sut.setOpen(true); assertThat(sut.allocate()).isEqualTo(expected); } This is easier but more complex. It depends on a multi-thousand line library with its own API. public void allocationOnlyPossibleWhenOpen() { LocalDateTime expected = LocalDateTime.now(); Clock mockClock = mock(Clock.class); when(clock.getTime()).thenReturn(expected); TimeAllocator sut = new TimeAllocator(mockClock); sut.setOpen(false); assertThat(sut.allocate()).isNull(); sut.setOpen(true); assertThat(sut.allocate()).isEqualTo(expected); } The 2nd example has: A versioned external dependency, externally versioned == opportunity for future conflict. Remember the java logging library wars? Today it's trivial to encounter conflicting spring dependencies on your classpath A complex (but convenient) reflection based implementation, the object has non-obvious behaviour with a clever implementation An entire api surface distinct from the components of your software system Tens of thousands of lines of opportunity for bugs, security risks or just plain old $$ cost to hide in Once you're able to see the world in complexity, it opens up a whole new dimension of cost & quality for your code. All this said, in practice complexity is just a consideration. Often the complexity is worth paying. I don't want to risk the impression that i'm saying never use mockito. If my argument is anything then it's consider the impact of complexity.
- closeparen 7y agoUsing a test framework that bends the rules of the language is far from simple. One of the things I appreciate about Go is that any mortal can understand how a unit test works: you "just" plug in something that satisfies the interface. However, we are spoiled to have implicitly satisfied interfaces, which can be declared on the consumer side without the implementation even knowing.
- BeetleB 7y ago> Adding interfaces whose only purpose is unit tests is not keeping the code simpler. Using a test library that automatically generates mocks for unit testing is what keeps the code simpler. I've yet to find a library for C++ that generates mocks without requiring interfaces, but I'll admit I'm not an expert on it. Can you recommend any? As an example, Google Mock/Test will require interfaces in a C++ code base. Of course, we may be disagreeing on what is meant by the term "interface".