Here is my class library code which I have C# and xUnit.
namespace XUnitSample.ClassLib
{
public class DataAccess : IDataAccess
{
public void AddPersonToPeopleList(List<Person> people, Person person)
{
// TDD: 01 - Write a unit test which 'shouldfail'
// If the 'shouldfail' unit test you wrote fail as expected,
// then your unit test is 'passed'.
//people.Add(person);
// TDD: 02 - Write a unit test which 'shouldpass'.
// If the 'shouldpass' unit test you wrote fail as expected,
// then your unit test is 'passed'.
people.Add(person);
}
}
}
And for my xUnit, I have one test class with 2 unit tests method.
public class DataAccessTest
{
[Fact]
// TDD: 01 - Write a unit test which "shouldfail"
// If the "shouldfail" unit test you wrote fail as expected,
// then your unit test is "passed".
public void AddPersonToPeopleList_ShouldFail()
{
// Arrange
var newPerson = new Person() { Id = 1, FullName = "John" };
var people = new List<Person>();
// Act
var dataAccess = new DataAccess();
dataAccess.AddPersonToPeopleList(people, newPerson);
// Assert
// If count is not 1, unit test is 'passed'
Assert.True(people.Count != 1);
// If people does not contain new person, unit test is 'passed'
Assert.DoesNotContain<Person>(newPerson, people);
}
[Fact]
//TDD: 02 - Write a unit test which 'shouldpass'.
// If the 'shouldpass' unit test you wrote fail as expected,
// then your unit test is 'passed'.
public void AddPersonToPeopleList_ShouldPass()
{
// Arrange
var newPerson = new Person() { Id = 1, FullName = "John" };
var people = new List<Person>();
// Act
var dataAccess = new DataAccess();
dataAccess.AddPersonToPeopleList(people, newPerson);
// Assert
// If count == 1, unit test is 'passed'
Assert.True(people.Count == 1);
// If people contain new person, unit test is 'passed'
Assert.Contains<Person>(newPerson, people);
}
}
Is this what it means by applying TDD principles of writing a unit test which shouldfail
first and then write unit test which shouldpass
?
-
2This looks strange. The explanation for "should pass" and "should fail" are letter-for-letter identical. That makes no sense.Jörg W Mittag– Jörg W Mittag06/15/2020 05:08:19Commented Jun 15, 2020 at 5:08
-
@JörgWMittag The copy paste bandit has struck again.candied_orange– candied_orange06/15/2020 05:56:29Commented Jun 15, 2020 at 5:56
1 Answer 1
"Should fail" and "should pass" refer to the same test at different points in time, it doesn't mean that you write two separate tests. The TDD process starts with writing a failing unit test (failing because you haven't implemented the expected behavior yet) and then writing the code to make it pass.
In your example, the expected behavior is described by AddPersonToPeopleList_ShouldPass
and this is the only test you need. You should write this before implementing the AddPersonToPeopleList
method (at this point, the test will fail) and then go add the implementation (people.Add(person)
) after which the test should pass.
-
1Not 100% sure this was meant to be the red green cycle. I write "should fail" tests that are meant to cause exceptions. They pass when they do. We call them the "rainy day" tests.candied_orange– candied_orange06/15/2020 06:02:18Commented Jun 15, 2020 at 6:02
-
1See also the happy pathcandied_orange– candied_orange06/15/2020 06:04:55Commented Jun 15, 2020 at 6:04
-
Many test frameworks have
shouldFail
orassert_fail_assertion
/assert_raise
orassertThrows
for that use case.Jörg W Mittag– Jörg W Mittag06/15/2020 06:58:24Commented Jun 15, 2020 at 6:58 -
Based on the sample code in the question, it did seem like the OP was confused about the red-green cycle. Both test cases have the same arrange and act steps, but opposite assertions. I would expect the "rainy day" tests you describe to have a different setup (such as invalid input).casablanca– casablanca06/15/2020 07:32:13Commented Jun 15, 2020 at 7:32
-
Also the commented out code in the SUT (under TDD: 01) suggests that the OP was indeed trying to write a test case that "passed" before the code was written.casablanca– casablanca06/15/2020 07:34:22Commented Jun 15, 2020 at 7:34