Making a Code Snippet More Testable
Setting Things Up
This exercise requires cmake version 3.12 or greater. This is available in CSIL at /usr/shared/CMPT/faculty/wsumner/base/bin/cmake
.
It is also presently configured to allow C++17 and later. In order for that to work, you need such a compiler available in your environment. Again, this should be working out of the box in CSIL, if that is what you require.
Goal
In this exercise, I have given you some broken and buggy code. I want you to write some unit tests for it using GoogleTest. I have provided you with a project template, available here:
https://www2.cs.sfu.ca/~wsumner/teaching/473/music-manager.tar.gz
I will not be giving you step by step instructions. I will provide you with objectives and things to consider, and I want you to modify the code and experiment in order to understand what is involved with the problem and how to achieve the objectives.
At a high level, I want you to walk away with a better understanding of using GoogleTest, as well as an understanding of how to write test fakes manually and what automated test fake (or mocking) infrastructures are achieving behind the scenes.
Note: This is intended to be an in class exercise. In class, I am happy to help you with questions about it. Outside class, you should work through these things on your own or bring questions to office hours.
The Objectives
1) Get Familiar with GoogleTest
Before trying to do anything too complex, you should get comfortable with the basic structure of a unit test in the framework you are using.
To start out, you could try writing a unit test for the Song
class. It is pretty simply, but it also makes use of some bad behaviors that might make it easy for a bug to have slipped through.
There isn't much there, but what can you test about a Song
? Try writing out a unit test for it and making sure that it does what you think it does.
Better still, can you think of a way to rewrite the class to make it so that no testing was necessary? If you can avoid tests by making software that prevents some types of defects, it decreases your testing burden.
2) Understand the challenges in testing playSongBy
Try to test the playSongBy
method. You will find this challenging, as the code has been designed to be rather untestable. Why is the code hard to test? Read through its dependencies to get a clearer picture.
3) Manually refactor the code to make it testable
Based on your observations from (2), what things need to change in order to make testing this method realistic? Do you need to change the types that are present in the program? If so, how should you change them? If not, why can you avoid changing them?
Refactor the code manually (without any mocking framework) in order to make the code testable. Testability can be relative, so we can constrain the problem somewhat. Consider a single user story for playSongBy where the music database contains only a single song and the user tries to play a song by the artist of that song. How should the system behave? Make sure that your refactoring can support at least this test.
4) Actually write the test from (3)
If you didn't already, write the simple test case planned out in step (3). It may cause you to refactor your design further.
5) Avoid the boilerplate and bespoke refactoring.
Your work in 3 and 4 may have introduced a substantial amount of additional boilerplate into the testing code. Use GoogleMock to refactor that boilerplate out of the tests. You should also find that it makes the tests easier to write.
6) Thinking about additional user stories
We constrained things pretty tightly. The database in the previous example had only a single song. What if the database had more songs than that. Are there other complexities that might have to be handled? How would you need to refactor the code in order to make sure that it is still testable.