Developers know that it’s important to test their code. There is a difference, though, between knowing a thing is important and actually doing that thing. Oftentimes developers prioritize extending their code rather than dedicating time to writing tests for the code that they’ve already completed.
So I wanted to take some time to explore testing in code. What is it, why does it need to be done? Are there different types of tests?
What is testing and why does it need to be done?
In the past, software testing was a very manual task. You would run your code in a test environment and then follow some pre-determined series of clicks around the user interface to see if anything broke. This way of testing becomes incredibly time-consuming as a piece of software scales up, not to mention it becomes very tedious and therefore is prone to errors.
The solution to this is automation. We now write tests for our code that will spare us from having to make sure we perform just the right clicks to check all parts of our app. Automated testing also makes large scale refactoring much less of a headache, allowing you to determine whether you are breaking things in close to real-time.
Are there different types of tests?
Actually, yes! There is actually the concept of a test pyramid, which describes different layers of tests and the general nature of these tests. Different sources may give different names to the layers, but all agree on the idea a decreasing amount of granularity (or the amount of testing needed at each layer) as you move up the pyramid (hence its shape).
The idea here is to make sure you write a large number of small unit tests that are fast. The middle layer should have a moderate amount of coarse-grained tests. There should only be a few high level tests. This idea of decreasing the number of tests the higher up you go (and increasing their breadth of scope) will help establish a healthy, fast and maintainable test suite.
Ok, so what are each of these layers in the testing pyramid?
Just like the name implies, these tests only test a very specific unit, or single part, of your application. You’re not testing any dependencies, integrations or frameworks. These tests essentially focus on one section of code to verify that it is doing what it’s supposed to be doing. How you define a unit depends on your app and how fine-grained you need to get; a unit could be anything from an individual function, a method, a procedure, a module, or an object.
Unit tests have a number of benefits.
- You can be secure in the knowledge that your code is working. If everything seems to work initially and then you deploy your app without testing…you are often left with the feeling that something could break at any moment. With unit tests, you can drastically cut down on that fear. You can make sure to fix bugs early on in the development cycle and increase confidence in your code when it’s deployed.
- With proper unit tests, all developers involved in a project can better understand what’s going on in the code and changes can be made much quicker. It also helps structure the code better at the beginning of a project…thinking about how code can be unit-tested will help avoid messy code that is responsible for way too many actions.
- Understanding edge cases is also made easier by unit testing. If a parameter fall outside an expected range, contains too few or too many characters, or is null, how do you handle that? All this becomes clearer as you build your tests.
- If you need to re-use code, proper unit tests can help get that up and functional in a fraction of time. You can migrate over code and its associated unit tests!
These tests come into play when it’s time for your code to start communicating. This communication could be with another module within your app, or some kind of database or file system. Integration tests to check on this communication are slightly more complicated than unit tests, as they require special testing environments and the initialization of dependencies, among other things.
The previous two tests check that the app works the way you, the developer, want it to work. The final layer of the testing pyramid essentially looks at the app from a user’s point of view and makes sure your app works from end to end as expected.
Hopefully this article gave you a general idea of what testing is all about. In future articles, I’m going to take a deeper dive into unit testing and give some more concrete examples. Happy coding (and testing)!