loading...

How do you name your tests?

n_develop profile image Lars Richter ・1 min read

As you might know, I'm a big fan of unit testing and TDD. But I often go back and forth on the naming of my unit tests. There are many popular naming schemes for unit tests. A few of them are:

[MethodUnderTest]_[TestedState]_[ExpectedBehavior]

That's a classical naming scheme.

ReadFrom_FileDoesNotExist_ThrowsException

[MethodUnderTest]_[ExpectedBehavior]_[TestedState]

This is pretty similar to the first scheme. Personally, I like this one a little better than the first one. This one reads a little more naturally. For example:

ReadFromFile_ThrowsException_FileDoesNotExist

It reads almost like "WriteToFile throws an exception if file does not exist".

Should_[ExpectedBehavior]_When_[TestedState]

Should_ThrowException_When_FileDoesNotExist

This also reads almost like a "normal" sentence.

When_[TestedState]_Expect_[ExpectedBehavior]

When_FileDoesNotExist_Expect_WriteToFailToFail

Given_[Preconditions]_When_[TestedState]_Then_[ExpectedBehavior]

Given_ReportIsWrittenToFile_When_FileDoesNotExist_Then_ExceptionIsThrown

JustDescribeWhatIsGoingOnAndWhatShouldHappen

This is something I fall back to from time to time. In these cases, my test read something like this:

OrderProcessorThrowsAnExceptionInCaseOfMissingCustomer

These are just a few examples. Feel free to add some more naming schemes in the comments.

Whats your favorite naming scheme? Are there naming schemes you do not like?

Posted on by:

n_develop profile

Lars Richter

@n_develop

I'm a father, husband, developer, .NET-fan, blogger and tea-driven developer.

Discussion

pic
Editor guide
 

In Python land I typically name my methods test_[method under test]_[expected behavior]?_when_[preconditions], so my tests look like:

def test_extract_name_when_present(...):
    ...

def test_extract_name_fails_when_missing(...):
    ...

With my recent adoption of pytest for a lot of stuff, though, I also parameterize tests where I can which ends up making the test method names more generic.

 

I like parameterized tests as well. It's a nice way to cover multiple cases, that share the same assert statements.

I'm not great at Python. Is the "test_" at the beginning of the method required for the testrunner to identify the tests, or is it "just" convention?

 

Yep, that's often the pattern that a test runner looks for! I think most can be customized to find other patterns too, and I recently saw a pytest plugin that makes it easy not to have to type "test" so many times in code you already know is tests.

 

Lately I've been writing mostly JS, and I am quite fond of the way Jest/mocha tests are written:

describe("SomeClass", () => {
  it("does something when something happens", () => {
    // Test code
  }
}

This way you actually write coherent sentences to describe your tests, not needing some elaborate convention.

 

That reads pretty nice, indeed. I should definitely check if there is something comparable for C#.

 

I'm learning Go right now and found, that it has a similar concept.

func TestSum(t *testing.T) {
    t.Run("collection of 5 elements", func(t *testing.T) {
        numbers := []int{1, 2, 3, 4, 5}

        got := Sum(numbers)
        want := 15

        if want != got {
            t.Errorf("got '%d' want '%d', %v", got, want, numbers)
        }
    })
    t.Run("collection of any size", func(t *testing.T) {
        numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}

        got := Sum(numbers)
        want := 36

        if want != got {
            t.Errorf("got '%d' want '%d', %v", got, want, numbers)
        }
    })
}

I like it.

 

Really great list! I didn’t realize there were actual naming patterns. I’m usually pretty lazy and write something like test[method name][input/state].

If I were more disciplined, I might follow something that mirrors what I was taught. In particular, I was taught to follow a first, middle, last and 0, 1, many test pattern, so that might be a good way to name tests as well.

 

Interesting. I learned writing Tests with the "0,1,some,lots,oops" pattern. It differentiates between "some" data and "lots of" data. And "oops" means handling error cases.

 

I choose Should_[ExpectedBehavior]When[TestedState] way to describe my test because when I come back and read my test, I feel this way make the test more readability, naturenality

 

Readability is key. And yes, this pattern is readable.
That's why I do like the Given_[Preconditions]_When_[TestedState]_Then_[ExpectedBehavior] pattern. It also reads like a normal sentence.