Lesson Wednesday

At the end of the last lesson, we wrote a test to confirm Item objects can save a description to a Description property. We use "arrange, act, assert" to write our test. We're now ready to make sure the test fails.

3. Confirm the Test Fails

If we run $ dotnet test in the ToDoList.Tests directory, we'll see errors:

ModelTests/ItemTests.cs(20,26): error CS1729: 'Item' does not contain a constructor that takes 1 arguments [/Users/epicodus_staff/ToDoList.Solution/ToDoList.Tests/ToDoList.Tests.csproj]
ModelTests/ItemTests.cs(21,31): error CS1061: 'Item' does not contain a definition for 'Description' and no accessible extension method 'Description' accepting a first argument of type 'Item' could be found (are you missing a using directive or an assembly reference?) [/Users/epicodus_staff/ToDoList.Solution/ToDoList.Tests/ToDoList.Tests.csproj]

This isn't technically a test failure message. It's actually a compiler error because the Item class doesn't have a constructor or a Description property. As a result, our test won't even run.

4. Implement the Behavior with Minimal Code

Let's continue adding behavior to get beyond the compiler error. Let's declare a constructor that takes a description as a parameter and create a Description property. We can use auto-implemented properties to do this:

ToDoList.Solution/ToDoList/Models/Item.cs
namespace ToDoList.Models
{
  public class Item
  {
    public string Description { get; }

    public Item(string description)
    {
      Description = description;
    }
  }
}

This is straightforward. Note that we only add get;, not set; to our property. Our test doesn't need a setter.

If we try running the test, we get another compiler error:

ModelTests/ItemTests.cs(12,26): error CS7036: There is no argument given that corresponds to the required formal parameter 'description' of 'Item.Item(string)' [/Users/epicodus_staff/ToDoList.Tests/ToDoList.Tests.csproj]

If we take a look at our tests, we can identify the problem in our first test: Item newItem = new Item();. Our Item class now expects an argument. Let's update that test:

ToDoList.Solution/ToDoList.Tests/ModelTests/ItemTests.cs
    public void ItemConstructor_CreatesInstanceOfItem_Item()
    {
      Item newItem = new Item("test"); //We pass in "test" as an argument here.
      Assert.AreEqual(typeof(Item), newItem.GetType());
    }

Now both of our tests are passing.

When we're following "Red, Green, Refactor" we should be identifying behaviors that remain true for the life of the program. Ideally, we should rarely have to go back and edit previous tests. In fact, editing tests to make them pass can be dangerous. We don't want to risk creating falsely-passing tests. However, as applications grow in size, it's occasionally required to edit previous tests. Nonetheless, it should be avoided where possible.

5. Confirm the Test Passes

We can confirm our tests are passing now.

6. Confirm Previous Tests Pass

After these changes we can see both tests are passing:

Total tests: 2. Passed: 2. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 0.9867 Seconds

1. Identify the Simplest Behavior

What's the next simplest behavior our application needs? Well, in addition to retrieving an Item's description, we'll also want to be able to set or alter an Item's description.

2. Write a Coded Test

Here's our new test. We use "arrange, act, assert" to organize it:

ToDoList.Solution/ToDoList.Tests/ModelTests/ItemTests.cs
...

    [TestMethod]
    public void SetDescription_SetDescription_String()
    {
      //Arrange
      string description = "Walk the dog.";
      Item newItem = new Item(description);

      //Act
      string updatedDescription = "Do the dishes";
      newItem.Description = updatedDescription;
      string result = newItem.Description;

      //Assert
      Assert.AreEqual(updatedDescription, result);
    }

...

This is very similar to our last test. The only difference is that we also set a new Description for our Item instance.

3. Confirm the Test Fails

If we run our tests, we'll receive a compiler error:

ModelTests/ItemTests.cs(32,7): error CS0200: Property or indexer 'Item.Description' cannot be assigned to -- it is read only [/Users/epicodus_staff/ToDoList.Tests/ToDoList.Tests.csproj]

This is pretty descriptive. We don't have a setter method yet. Our test doesn't lead to a true fail because it results in a compiler error. Let's fix the error and see what happens.

4. Implement the Behavior with Minimal Code

We can add a setter with minimal effort:

ToDoList.Solution/ToDoList/Models/Item.cs
namespace ToDoList.Models
{
  public class Item
  {
    // We add set; to the line below.
    public string Description { get; set; }

    public Item(string description)
    {
      Description = description;
    }
  }
}

5. Confirm the Test Passes

When we run $ dotnet test, our latest test passes.

6. Confirm Previous Tests Pass

In fact, all tests are passing:

Total tests: 3. Passed: 3. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 0.9918 Seconds

7. Check for Refactoring

We've already added auto-implemented properties so we don't have any further opportunity to refactor.

Lesson 15 of 20
Last updated April 14, 2022