This is the second story of . And it’s about the role of tests in software writing. Road to Simplicity ( ) The first part is about the goal of the series and hexagonal architecture Test and correctness I think that it’s inappropriate to associate with . After all with a test we can verify that a software module (e.g. a function) returns an expected output with a given input. But we cannot prove correctness in this way. We can prove correctness mathematically. And this is what we do to prove algorithms correctness. test verification of correctness We can see tests as experiments on the software system. And the below quote expresses concisely the above concept: No amount of experimentation can ever prove me right; a single experiment can prove me wrong Albert Einstein So, at most, a test could prove wrongness… Fear of change Software aren’t static system. They are in evolution. We can add or delete a feature. We can change its structure. And it changes according the solved problem. There are a of reason to change. lot However, with an evolution, we can break something that in the past. This event is called . Eventually we can find regressions manually. But this is a bad road because we could change: worked regression a software with a lot of use case. So this method is not efficient; a software that we didn’t write. So we didn’t know every aspect; a software that we wrote a long time ago. So we could forget some aspect. For these reasons we need a tool that guarantees to us non-regression. This tool is test. Tests free us from the fear of change. Indeed if a test fail we can investigate and fix the issues. Otherwise we can rest assured: . This implies code malleability. we didn’t break something that worked in the past This is the most evident advantage. But there is another subtler. Yourself as client of yourself The goal of is to express a methodology to reach simplicity. And there is a connection with tests. Road to Simplicity In the last story we already defined a use case. In reality I write use case and its test simultaneously. These tests are crucial because use cases represents what our software does. And they guarantees simplicity because when we write tests we’re the client of ourselves. And, as programmers, we love simple and clean interface. Furthermore, because test is more code, we don’t want to write unnecessary lines. In this way we are forced to write the most minimal and simplest interface. Code In this series I use a demo project to express concretely these ideas. It's written in Java 11 with reactive programming thanks to . The project is hosted on . ReactiveX github The software analyzes the capabilities (e.g. java version) of the machine. Then it will expose them through REST API. In the previous part we expressed our use case ( ) as: GetCapabilitiesUseCase { ; } public interface GetCapabilitiesUseCase Single<Capabilities> getCapabilities () So here the first test definition. I’m using with test facility. It verifies that the returned capabilities object is correct. We are passing to the use case factory two mocked port out implementations: JUnit 5 ReactiveX { { String javaVersion = randomString(); Long networkSpeed = randomLong(); GetCapabilitiesUseCase useCase = UseCaseFactory.getCapabilitiesUseCase( () -> Single.just(javaVersion), () -> Single.just(networkSpeed) ); TestObserver<Capabilities> useCaseObserver = useCase .getCapabilities() .test(); assertTrue(useCaseObserver.await( , TimeUnit.MILLISECONDS)); useCaseObserver .assertResult( Capabilities(javaVersion, networkSpeed)); } { UUID.randomUUID().toString(); } { ThreadLocalRandom.current().nextLong(); } } class GetCapabilitiesUseCaseTest @Test Throwable void ok () throws 100 new String private randomString () return Long private randomLong () return During the writing I discovered that there is a room of improvement. Currently our use case could return negative network speed. This is possible because the class allows these values. So I improved its constructor with an exception: Capabilities { { .javaVersion = javaVersion; .networkSpeed = networkSpeed; ( .networkSpeed < ) IllegalArgumentException( ); } String javaVersion; Long networkSpeed; } @Value @Builder public class Capabilities public Capabilities (String javaVersion, Long networkSpeed) this this if this 0L throw new "Network speed should be greater than 0!" private final private final Then I added the test class about : Capabilities { { String javaVersion = randomString(); Long networkSpeed = randomNegativeLong(); { Capabilities(javaVersion, networkSpeed); IllegalStateException( ); } (IllegalArgumentException e) { } } { UUID.randomUUID().toString(); } { ThreadLocalRandom.current().nextLong( , Long.MAX_VALUE) * - ; } } class CapabilitiesTest @Test Throwable void with_negative_network_speed () throws try new throw new "Invalid capabilities built!" catch String private randomString () return Long private randomNegativeLong () return 1L 1L And I updated the use case test: { { String javaVersion = randomString(); Long networkSpeed = randomNonNegativeLong(); GetCapabilitiesUseCase useCase = UseCaseFactory.getCapabilitiesUseCase( () -> Single.just(javaVersion), () -> Single.just(networkSpeed) ); TestObserver<Capabilities> useCaseObserver = useCase .getCapabilities() .test(); assertTrue(useCaseObserver.await( , TimeUnit.MILLISECONDS)); useCaseObserver .assertResult( Capabilities(javaVersion, networkSpeed)); } { UUID.randomUUID().toString(); } { ThreadLocalRandom.current().nextLong( , Integer.MAX_VALUE); } } class GetCapabilitiesUseCaseTest @Test Throwable void ok () throws 100 new String private randomString () return Long private randomNonNegativeLong () return 0L I run the tests and they are successful. At this point we can extend our domain without fear of regressions. We have tests that protect us. Furthermore we have a neat use case interface. Conclusion For this story that’s all. I like to stress that tests are not for the present. We are not verifying with them software correctness. Tests are for the future because they guarantee malleability, extensibility and maintainability. At the end they guarantee code simplicity. Stay tuned! :D Resources JUnit 5 ReactiveX Test Driven Development Monkey Testing