Skip to main content
added gerkin link
Source Link
StuperUser
  • 6.2k
  • 1
  • 31
  • 57

A problem with telling a story with unit tests is that it doesn't make explicit that unit tests should be arranged and run entirely independently of each other.

A good unit test should be completely isolated from all other dependent code, it's the smallest unit of code that can be tested.

This gives the benefit that as well as confirming the code works, if a test fails you get the diagnosis for exactly where the code is wrong for free. If a test isn't isolated you have to look at what it depends on to find out exactly what's gone wrong and miss out on a major benefit of unit testing. Having the order of execution matter can also raise a lot of false negatives, if a test fails it's possible for the following tests to fail despite the code they test working perfectly fine.

A good article in more depth is the classic on dirty hybrid tests.

To make the classes, methods and results readable the great Art of Unit testing uses the naming convention

Test Class:

ClassUnderTestTests

Test Methods:

MethodUnderTest_Condition_ExpectedResult

To copy @Doc Brown's example, rather than using [Setup] which runs before each test, I write helper methods to build isolated objects to test.

[TestFixture] public class AuthenticationTests { private Authentication GetAuthenticationUnderTest() { // create an isolated Authentication object ready for test } [Test] public void CreateAccount_WithValidCredentials_CreatesAccount() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); //Act Account result = codeUnderTest.CreateAccount("some", "valid", "data"); //Assert //some assert } [Test] public void CreateAccount_WithInvalidCredentials_ThrowsException() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); Exception result; //Act try { codeUnderTest.CreateAccount("some", "invalid", "data"); } catch(Exception e) { result = e; } //Assert //some assert } } 

So the failing tests have a meaningful name that gives you some narrative about exactly what method failed, the condition and the expected result.

That is how I've always written unit tests, but a friend has had a lot of success with Gerkin.

A problem with telling a story with unit tests is that it doesn't make explicit that unit tests should be arranged and run entirely independently of each other.

A good unit test should be completely isolated from all other dependent code, it's the smallest unit of code that can be tested.

This gives the benefit that as well as confirming the code works, if a test fails you get the diagnosis for exactly where the code is wrong for free. If a test isn't isolated you have to look at what it depends on to find out exactly what's gone wrong and miss out on a major benefit of unit testing. Having the order of execution matter can also raise a lot of false negatives, if a test fails it's possible for the following tests to fail despite the code they test working perfectly fine.

A good article in more depth is the classic on dirty hybrid tests.

To make the classes, methods and results readable the great Art of Unit testing uses the naming convention

Test Class:

ClassUnderTestTests

Test Methods:

MethodUnderTest_Condition_ExpectedResult

To copy @Doc Brown's example, rather than using [Setup] which runs before each test, I write helper methods to build isolated objects to test.

[TestFixture] public class AuthenticationTests { private Authentication GetAuthenticationUnderTest() { // create an isolated Authentication object ready for test } [Test] public void CreateAccount_WithValidCredentials_CreatesAccount() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); //Act Account result = codeUnderTest.CreateAccount("some", "valid", "data"); //Assert //some assert } [Test] public void CreateAccount_WithInvalidCredentials_ThrowsException() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); Exception result; //Act try { codeUnderTest.CreateAccount("some", "invalid", "data"); } catch(Exception e) { result = e; } //Assert //some assert } } 

So the failing tests have a meaningful name that gives you some narrative about exactly what method failed, the condition and the expected result.

A problem with telling a story with unit tests is that it doesn't make explicit that unit tests should be arranged and run entirely independently of each other.

A good unit test should be completely isolated from all other dependent code, it's the smallest unit of code that can be tested.

This gives the benefit that as well as confirming the code works, if a test fails you get the diagnosis for exactly where the code is wrong for free. If a test isn't isolated you have to look at what it depends on to find out exactly what's gone wrong and miss out on a major benefit of unit testing. Having the order of execution matter can also raise a lot of false negatives, if a test fails it's possible for the following tests to fail despite the code they test working perfectly fine.

A good article in more depth is the classic on dirty hybrid tests.

To make the classes, methods and results readable the great Art of Unit testing uses the naming convention

Test Class:

ClassUnderTestTests

Test Methods:

MethodUnderTest_Condition_ExpectedResult

To copy @Doc Brown's example, rather than using [Setup] which runs before each test, I write helper methods to build isolated objects to test.

[TestFixture] public class AuthenticationTests { private Authentication GetAuthenticationUnderTest() { // create an isolated Authentication object ready for test } [Test] public void CreateAccount_WithValidCredentials_CreatesAccount() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); //Act Account result = codeUnderTest.CreateAccount("some", "valid", "data"); //Assert //some assert } [Test] public void CreateAccount_WithInvalidCredentials_ThrowsException() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); Exception result; //Act try { codeUnderTest.CreateAccount("some", "invalid", "data"); } catch(Exception e) { result = e; } //Assert //some assert } } 

So the failing tests have a meaningful name that gives you some narrative about exactly what method failed, the condition and the expected result.

That is how I've always written unit tests, but a friend has had a lot of success with Gerkin.

Source Link
StuperUser
  • 6.2k
  • 1
  • 31
  • 57

A problem with telling a story with unit tests is that it doesn't make explicit that unit tests should be arranged and run entirely independently of each other.

A good unit test should be completely isolated from all other dependent code, it's the smallest unit of code that can be tested.

This gives the benefit that as well as confirming the code works, if a test fails you get the diagnosis for exactly where the code is wrong for free. If a test isn't isolated you have to look at what it depends on to find out exactly what's gone wrong and miss out on a major benefit of unit testing. Having the order of execution matter can also raise a lot of false negatives, if a test fails it's possible for the following tests to fail despite the code they test working perfectly fine.

A good article in more depth is the classic on dirty hybrid tests.

To make the classes, methods and results readable the great Art of Unit testing uses the naming convention

Test Class:

ClassUnderTestTests

Test Methods:

MethodUnderTest_Condition_ExpectedResult

To copy @Doc Brown's example, rather than using [Setup] which runs before each test, I write helper methods to build isolated objects to test.

[TestFixture] public class AuthenticationTests { private Authentication GetAuthenticationUnderTest() { // create an isolated Authentication object ready for test } [Test] public void CreateAccount_WithValidCredentials_CreatesAccount() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); //Act Account result = codeUnderTest.CreateAccount("some", "valid", "data"); //Assert //some assert } [Test] public void CreateAccount_WithInvalidCredentials_ThrowsException() { //Arrange Authentication codeUnderTest = GetAuthenticationUnderTest(); Exception result; //Act try { codeUnderTest.CreateAccount("some", "invalid", "data"); } catch(Exception e) { result = e; } //Assert //some assert } } 

So the failing tests have a meaningful name that gives you some narrative about exactly what method failed, the condition and the expected result.