Writing unit tests faster and more efficiently

Thanh Tung Nguyen
4 min readMay 31, 2022

In this article, I want to share with you how to write unit tests faster and more efficiently.

1. Developers who don’t write tests!

▪ We don’t have time to write tests!

▪ Unit tests are waste of time. They slow you down and decrease your productivity!

▪ I don’t know how to write unit tests!

2. What is Unit Test?

▪ A way of testing the smallest piece of code referred to as a unit that can be logically isolated in a system.

▪ Focus on the functional correctness of standalone modules.

3. Developers should write unit tests

▪ Test your code frequently and in less time.

▪ Catch more bugs before deploying.

▪ Deploy your application with more confidence.

▪ Refactor your code with confidence.

▪ Write cleaner and maintainable code.

4. How can we write unit tests faster and more efficiently?

4.1. Prerequisites of Effective Unit Tests

▪ Clean code

▪ Testable design

▪ Context-aware

▪ Understanding of unit testing

4.2. Qualities of Effective Unit Tests

▪ Clean and simple

▪ High-value

▪ Flexible

4.3. Naming a unit test

[MethodUnderTest]_[Scenario]_[ExpectedResult]

▪ MethodUnderTest is the name of the method you are testing.

▪ Scenario is the condition under which you test the method.

▪ ExpectedResult is what you expect the method under test to do in the current scenario

4.4. Test Organization

4.4. AAA pattern

All unit tests should follow the AAA pattern: arrange, act, assert. If a test has multiple arrange, act, or assert sections, that’s a sign that the test verifies multiple units of behavior at once. If this test is meant to be a unit test, split it into several tests one per each action.

Naming conventions

  • MethodName_StateUnderTest_ExpectedBehavior

IsAdult_AgeLessThan18_False

WithdrawMoney_InvalidAccount_ExceptionThrown

  • Should_ExpectedBehavior_When_StateUnderTest

Should_ThrowException_When_AgeLessThan18

Should_FailToWithdrawMoney_When_InvalidAccount

  • Given_Preconditions_When_StateUnderTest_Then_ExpectedBehavior

Given_UserIsAuthenticated_When_InvalidAccountNumberIsUsedToWithdrawMoney_Then_TransactionsWillFail

Asserting too many expectations makes it harder to find why the test actually failed.

Three separate tests improve precision.

4.5. High Precision

4.6. Improved readability of test source code

▪ Using an Assertion library to further improve test readability.

[Subject] [action] [object]

▪ Better, more descriptive failure messages may prevent the need for debugging through the test.

4.7. Improved readability of test source code

▪ Reuse test fixture initialization.

▪ Parameterized tests help reduce the amount of code needed for similar tests.

4.6. Tips and Tricks

In programming, we have two types of functions

Query functions

▪ You should write a test and verify that your function is returning the right value

▪ You might have multiple execution paths in that function. In that case, you should test all the execution paths and make sure that each execution path results in the right value.

Command functions

▪ If the outcome is to change the state of an object in memory, you should test that the given object is now in the right state.

▪ If the outcome is to talk about an external resource like a database or web services, you should verify that the class on the test, is making the right call to these external dependencies

Writing test faster

▪ Save time on coding/typing to create unit test code with xUnit Code Snippets

▪ Auto-mocking with AutoFixture

▪ Private methods and insufficient coverage, you should be extracted into a separate class

▪ Let’s practice with it for 10,000 hours

5. Reference

https://github.com/Moq/moq4/wiki/Quickstart

https://xunit.net/

https://andrewlock.net/creating-strongly-typed-xunit-theory-test-data-with-theorydata/

https://andrewlock.net/creating-parameterised-tests-in-xunit-with-inlinedata-classdata-and-memberdata/

--

--