Back to the basics: Tests, part 3
When we start to write a test, we must have a well-defined goal that will be the test proposes and what we want. Normally, we think in three principal types:
- Common cases: The common scenarios, for example the sum function, let's test the sum operations.
- Error cases: All scenarios that give us an error, getting the sum function, if I pass a letter as parameter?
- Boundary cases: This is the weird thing that none expected to happen, but surprise! Like pass a huge number to that the language cannot compute, for example.
Of course, all these types depends on the level of stress that you want to bring to the tests cases and how much programming defense you applied into your code.
But the reality is harder, the functions aren't only sums or something like that, we have a lot of complexity into our apps, like: external request, timers, databases, data inconsistent, etc. So to threat these scenarios, we have some tests tools to help with.
- Mocks: Objects that simulate the behavior of real objects in the system, the best example is a database, we don't want that every time we run our tests, the application connects to the database and make operations there. So, we use a mock to simulate a database at the test runtime.
- Stubs: A simplified implementation of an object or module that is used to replace the real object or module in a test scenario. Think that we need to get some data of an external system, instead of make the actual request for the external system, we add a stub to return what that function will return, without have the external dependency.
- Dummies: A placeholder object that is used as a parameter in a function or method call to satisfy the compiler or the code syntax. You need an object, but the constructor requires a lot of others things, you create a dummy to satisfy the constructor parameters that you don't care for the test.
- Spies: Used to verify that the code under test is calling the correct methods on its dependencies with the correct arguments. Very common on functions that do not have any return or fire-forget, you will "spy" if the action was actually called inside for another method, for example.
- Fakes: A simplified implementation of an object or module that is used to replace the real object or module in a test scenario. Very common in mutation tests, where you change the original behavior to do the other thing.
Knowing these techniques is extremely valuable to write consistent tests across the whole application, but the heavy usage of these techniques can invalidate the trust of the tests, because sometimes you can overwrite your on system. We will see how to protect it later. Bye!