Recently, a friend of mine needed help with Java that they were writing for a class project. As a newcomer to software development, they were having trouble understanding the nuances of object oriented design, and I was happy to help. My first ask was for the code that they had written to date, so that I had an understanding of their current state. I absolutely love reading through the code of others, because it helps me learn new skills, and techniques, even if the developer I’m working with is new to the field.
After spending time reviewing the code, and the requirements of the project, I realized that what we needed was a set of unit tests. Over the past three years, my exposure to unit tests has increased significantly, and I can see the improvement in code quality because of it. While I can’t guarantee that there are unit testing frameworks for every programming language out there, it’s pretty damn close. In this case, I used JUnit because of my light previous experience with it, and because the code that I was reviewing was Java.
JUnit is a unit testing framework for the Java programming language. JUnit has been important in the development of test-driven development, and is one of a family of unit testing frameworks which is collectively known as xUnit that originated with SUnit. 1
I’m naturally disposed to be very procedural when it comes to software development and because of this, am accustomed (How many times can you get burned before you stop touching the hot stove?) to gathering requirements longer than most. In this case, I asked my friend what the requirements for the specific class was. They provided a list of methods, their respective arguments, and expected output from each which was perfect.
The next step was to crack open the JUnit User Guide so that I could refresh myself with syntax, and usage. At first glance, I realized that the framework had come a long way since I used it last, and I was really impressed!
I’m a fan of the IDEs from JetBrains. I still remember when I was first introduced to IntelliJ and how much I enjoyed writing code in an editor that performed auto complete saving my precious fingers from extra key strokes. IntelliJ has built-in support for JUnit and it’s incredibly easy to configure. The instructions are straight forward to follow (there are seven short steps). Once you complete them, you’ll have a new class named with the class you’re testing appended with the word ‘Test’.
In my case, this is what the framework looked like:
Java annotations (the terms prepended with an @ symbol) are wonderful. In the Block S3 Buckets post, I used a similar concept called Python Decorators which were inspired by Java annotations. Their intent is to augment the associated method at compilation time. JUnit has quite a few annotations which provide various functionality. When I created the Test class, I chose to add the setup and teardown methods, but only ended up using the teardown to nullify the objects used in each test.
The nice piece of unit tests is that you can name them whatever you want, and in fact, the more descriptive, the better. In this case, while the autogenerated tests are nice as placeholders reminding you what methods to test, you’ll eventually find that you need multiple tests for the same method. This ensures that you’re testing each execution path in the method (as best as possible). In the industry, this is typically called Code Coverage.
This brings me back to the requirements gathered earlier… remember those? ;) We want to make sure that the code we’re testing adheres to expectations. The first expectation, in my case was to ensure that the object was being instantiated properly. There were two constructors, using two different argument sets. I wrote two tests for each; one to ensure that the constructor was behaving as expected with valid data, and the other, with invalid data.
Note, that I’m using two different annotations here than what was referenced earlier. In this case, @ParameterizedTest gives me the ability to run the test over a set of data. If any individual run of the test fails, then the entire test fails providing you with a report of which particular dataset caused it to fail (extremely helpful in troubleshooting). @ValueSource simply provides the list of data to iterate on.
In the test below, I’m using @CsvSource which enables me to test a set of data for each run (instead of one value).
Overall, this was a fantastic opportunity for me to help a friend out in their journey to learn how to write code. I’m a huge advocate in not only sharing your knowledge with others, but also ensuring that you also benefit in learning from the process. In this case, I certainly learned that implementing unit tests (even simple ones) was quite easy, and I expect to flip my development style to be more test-driven in the future.
Wikipedia contributors, “JUnit,” Wikipedia, The Free Encyclopedia, https://en.wikipedia.org/w/index.php?title=JUnit&oldid=913002828 (accessed October 10, 2019). ↩
Tweet to @kriation