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 Jun 16 '19 by:

n_develop profile

Lars Richter

@n_develop

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

Discussion

markdown guide
 

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.

 

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.

 

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.