Twitter LinkedIn Github

JetBrains

I try, as much as I can to practice TDD, because I truly believe that it helps me shape the design, and that is the primary objective of TDD, not tests. Testing is a nice side-effect. As such, tests serve as specifications; reading a test should give you a clear understanding of what the SUT does. However, reality is not always the case, so the more help you provide to your audience (including yourself), the better. Part of that resides in how you name your tests.

Action_Result_Condition

Let me first point out that I'm not too fond of method names having underscores, but I do find it no doubt easier to read. Which do you find easier?

GetCustomerShouldReturnActiveCustomer

or

GetCustomer_Should_Return_Active_Customer

Before continuing, let me also say that in the context of non-test methods, if you need to use underscores for naming methods, you're probably doing way too much in the method to begin with and it could probably be re-factored. However, tests are a special case.

A test validates certain functionality under specific conditions (or lack of them). By indicating this in the test name, it makes it not only easier to understand the specification, but to also validate the actual test. Take the following example:

   1: [TestMethod]
   2: public void ValidateGetActiveCustomer() {
   3:  
   4: }

without reading the code, you really don't know what that test is meant to do. All you know is that it validates a GetActiveCustomer. But under what conditions? Since the only reference you have is the code, if it's wrong, that is, the test is written incorrectly, you're pretty much lost. You're running that test and thinking all is ok when really it isn't.

Now let's take a look at the same test but with a different name

   1: [TestMethod]
   2: public void GetActiveCustomer_Returns_Customer_When_Given_Valid_Id() {
   3:  
   4: }

This clearly indicates the intentions of the test. At first sight, without even looking at the code, you know what the test is trying to accomplish, and thus providing you a basis by which to validate the actual test code.

You could say that the name is too long. So? You short on bytes? Or on display settings? You could also argue that the Returns_Active_Customer is redundant. Sure, it might be in this case, but that's because GetActiveCustomer more or less indicates what that particular action should do. But there are cases when this does not apply. Let's look at another example

   1: [TestMethod]        
   2: public void ValidateDeleteCustomer() {
   3:         
   4: }

ValidateDeleteCustomer, what does it do? When does it fail? When does it pass?

On the other hand, the following test is telling me not only under what conditions DeleteCustomer should work, but is also clearly indicating a requirement of the program: when a customer has no orders, you can delete it.

   1: [TestMethod]
   2: public void DeleteCustomer_Deletes_Customer_When_Customer_Has_No_Orders()
   3: {
   4:     
   5: }

Here's another example:

   1: [TestMethod]
   2: [ExpectedException(typeof(Exception))]
   3: public void DeleteCustomer_When_Customer_Has_Orders_Throws_Exception() {
   4:  
   5: }
   6:  

Again, as with GetActiveCustomer, we know that this test throws an exception by looking at the test attribute. However, this is something we don't see in a test view/run.

Irrelevant of whether you use underscores or not, use long names or short names, what is also very important is to establish a convention and stick to it. At the very least, all tests in a project should follow the same convention, and if you can get a consensus with your team across different projects, even better.