I am .net developer. I have been using TDD on my daily basis for 3 years now. From time to time, I am finding something new. Something what can possibly improve my skills and even give benefits for my employer. I am also a fluent syntax enthusiast, I use Moq for creating test doubles and fluentassertions for test assertions.
Test layouts
I like including comments following AAA (Arrange, Act, Assert) in my test methods. It makes me think about what is necessary in arrange section, what in act and in assert one as well. I always try to extract as much as possible from assert and put it into arrange section. In example below, there are input value of tested method and expected output extracted.
[Fact]
public void GetValue_WhenGivenNumberIs3_ShouldReturnFizz()
{
// arrange
var fizzBuzz = new FizzBuzz.FizzBuzz();
const int number = 3;
const string expected = "Fizz";
// act
var result = fizzBuzz.GetValue(number);
// assert
result.Should().BeEquivalentTo(expected);
}
The benefit of this extraction is a very well-composed assert section. We do not pay for each letter in our version control system, so for me, it looks like a default approach.
Do you also include this kind of comments in your tests?
Test libraries
Creating test libraries I name unit tests with suffix .Tests
, and integration tests with suffix .IntegrationTests
. First part of library name is name of tested library. I usually create test class (file) for single source code class. Rarely, when tested class is big enough, or there are so many case scenarios, I split it into several files, each for one method, or for group of methods which follows similar scenarios.
What are your feelings about test libraries? Is there something that I missed?
Naming conventions
Recently, I had a discussion with my coworkers about test method naming convention. We argued about keeping or leaving word "Should"
in test method name. This conversation left a deep scratch in my mind, I have been thinking about it so many times in the evenings after work. In our company we are following convention from this article, but personally I like extending it with words When
and Should
. Take a closer look on it:
-
{MethodName}_{StateUnderTest}_{ExpectedBehavior}
public void GetValue_3_Fizz()
-
{MethodName}_When{StateUnderTest}_Should{ExpectedBehavior}
public void GetValue_WhenGivenNumberIs3_ShouldReturnFizz()
With this approach, name of test method looks like a whole sentence. It makes them self-explanatory even for very young developers. For me, to be honest, test which follows this could be even taken as some kind of a documentation of use cases.
What do you think about it? Should I still use when/should? Would it be good to insist?
And one more question - am I ready to teach younger colleagues in testing approaches?
Top comments (9)
Hi, thanks for reply.
Referencing to point 1, I am aware of empty spacer approach. Still, I think, that it is easier to involve someone into TDD without any skills, when there is clear distinction between each section.
Fair enough. Within the context of a training exercise that's definitely an important factor. I was mostly talking about 'production code', where superfluous comments tend to decrease the signal-to-noise ratio (if ever so slightly).
That said, I strongly believe in the ability of (appropriately short) comments to add contextual information and remove potential misunderstanding, thereby increasing maintainability. And in the context of training, the AAA comments are exactly that.
Thanks again, I will keep that in my mind.
Very good point!
That all makes sense to me. I like the clear distinction between tests and integration tests based on the name of the projects, and I like the clear language in the naming of the tests.
When you start teaching your colleagues who are a little greener to unit testing, make sure they understand the concept of writing code that is testable. Writing code that uses good dependency injection patterns is a good practice for implementing any testable system.
If your colleagues are really sharp or if they have exposure to testing and mocking, they will maybe ask how to mock sealed classes, or how to stub out behavior from abstract classes they are extending, and why it may not be the best idea to code themselves into a testing trap by following those patterns themselves.
I will give a try to explaining sealed classes are not so easy to test. Maybe short introduction into wrapping would be enough here?
I would say so.
We add comments most of the time. Maybe it's a bit OCD but we like it that way.
We separate unit and integration tests into 2 different libraries, as running integration tests is less frequent than running unit tests.
The naming convention is fine. But we don't write should as the unit does something.
e.g
GetValue_WhenGivenNumberIs3_ReturnsFizz()
The sooner you involve the younger/new devs in unit testing it will serve the team in the long run. Go for it :)
Good article, thanks!
I'm currently using Go, and I find that Table Driven Tests are pretty valuable.
You would set up the table in your Arrange section, and the Act and Assert sections would be mostly combined.