Naming Tests: The importance of choosing names

In this lesson

Naming is very important and that’s no different when it comes to tests. In this lesson, I cover naming the location of your tests, naming the test classes and test functions.


Tap on time to skip ahead


In this lesson, I’m going to talk about naming tests. When I say naming tests, I’m going to talk about where they reside here in a folder. I’m going to talk about the name of the test itself, the class or the component, and then finally, I’m going to talk about the individual test function names.


The first thing I want to talk about is the location of the test. You’ll notice here that I have a component in a SwiftProtocolSQLite folder. This is a target or a project, in your language it might be different, for example, Java. I have a subfolder here, that might be called a package in some languages, that contains a component called SQLUpdateOperation.


The first thing you should notice is that the tests are separate. They are in a separate target, or folder or project. The other thing is that the tests themselves, reside in the same folders or packages as the components that they’re testing. I have a sql folder here which is identical to the name of the folder in the other project that contains the component that I’m testing. The main reason for this is that you don’t want your tests bundled with the code, that is the production code, you want the test to be separate.


Next is the name of the test itself. Let’s look at this component here. This is a test called SQLStatementBuilderTest. It is identically named to the component it’s testing called SQLStatementBuilder. The test itself, it’s obvious by looking at the name, it just has the word test appended to the end of the name. It should be obvious what component is being tested.


Integration tests are a little bit different. You’ll notice the structure that I have here in terms of folders or packages. Underneath that is a file that contains a number of components. I don’t have my integration tests in the same folder structure. That’s because an integration test, tests the entire subsystem and not individual components. So I don’t necessarily need to mirror the same folder structure.


The second thing you’ll notice is that the name of the integration test includes the word integration test. That makes it obvious that this is an integration test as opposed to a unit test, which has no special naming other than the fact that I have the word test at the end.


Functional tests are also a bit different. You’ll notice here that I have an application with a whole bunch of folders and classes and code in there. I have a folder, or project, here that contains possibly unit and integration tests and a separate folder that contains functional tests. Like the integration tests, I don’t have my functional tests in a specific folder, usually just at the root. I might name them a little bit differently. I might have different categories of functional tests. In this case, this is a smoke test. This just exercises various aspects of the UI touching each screen, verifying that I can go into each screen without it crashing. That’s why I named it that.


Let’s have a look now at the actual test names themselves. I’m going to look at a function. You can ignore- I’m using Swift and XCTest- you can ignore the prefix here because XCTest requires that all of my tests begin with the word test. This is how the framework identifies tests. Your framework may be different. For example, in Java you can annotate your test names with an annotation that identifies them as tests.


Here’s what we are going to focus on. The actual name of the test function is, in a unit test scenario, the name of the function that I’m testing on this component, which is the item that I’m testing. I would expect to find a buildInsertStatement function on this class, which we’ll look at in just a second.


The second part of the test function name is the scenario. I want to be descriptive but terse. I don’t want to write a paragraph here. The scenario is that I’m going to call buildInsertStatement_withNamedParameters.


The third section of the name is the expected outcome. Applying the same rule, I want to be descriptive but terse. The expected outcome in this case is generatesValidSQLInsertStatement.


If we scroll down slowly and look at all my test names, it should be obvious applying this algorithm to the test names, what exactly is happening. This makes it really easy when you eyeball these tests, exactly what is being tested, what the scenario is and what the expected outcome is. It also makes it very nice when you look at the test reports after the test has run, what these are doing and possibly which ones are failing.


Let’s look quickly at the name of the integration test function names to see that I’ve applied the same approach. What it is we’re testing on the subsystem, the scenario and the expected outcome. This applies across the board. I’ll scroll down here and you can kind of see the various test names. It should be very descriptive as to what exactly I’m testing, the scenario and the expected outcome.


Functional tests are a little different, as you can see. The names are slightly different because I’m not testing a specific function or on a particular component. Instead I’m somewhere in the app. The names that I’ve chosen are descriptive of where I’m at. This could be the equivalent of the scenario. I’m on the Champion Browser in this case, the expected outcome is that I can scroll to a specific champion. In this case, we can look at how I’ve named my function tests. Here I’m on the Champion Browser and I can tap a champion to see skins. On a Champion Skin Browser and I can scroll through the skins. Finally, I’m on the Champion Skin Browser and I can tap the back button to return to the Champion Browser.


Descriptive test names and function names are extremely important so that you can easily identify what is being tested and what is being expected.