Adding Test Classes

Add an MSTest test project beside your app, give it a reference to the app, and add a test class for each class you test.

Apprentice · Unit Testing · C# · Updated

After this lesson you can

  • Add an MSTest test project to a solution, with a reference to the project it tests
  • Write a test class with [TestClass] and [TestMethod], and run it

Key takeaways

  • dotnet new mstest -n TvRemote.Tests makes a test project, and dotnet add TvRemote.Tests reference TvRemote lets its tests see the app's classes.
  • [TestClass] marks a class that holds tests, and [TestMethod] marks a public void method that is one test.
  • A method without [TestMethod], or one that isn't public, isn't run as a test.
  • Test Explorer finds tests only after the solution builds, so build it when the list is empty.

Here's the Television class from Planning Unit Tests, in a console app named TvRemote:

namespace TvRemote;

public class Television
{
    public const int LowestChannel = 3;
    public const int HighestChannel = 15;

    public bool IsOn { get; private set; }
    public int CurrentChannel { get; private set; } = LowestChannel;

    public void TurnOn()
    {
        IsOn = true;
    }

    public void TurnOff()
    {
        IsOn = false;
    }

    // Goes up one channel, from the highest back to the lowest, and returns the new channel.
    // While the TV is off, nothing changes.
    public int ChannelUp()
    {
        if (IsOn)
        {
            CurrentChannel = CurrentChannel == HighestChannel ? LowestChannel : CurrentChannel + 1;
        }
        return CurrentChannel;
    }

    // Changes to the channel, if the TV is on and the channel exists. Returns whether it changed.
    public bool ChangeChannel(int channel)
    {
        if (!IsOn || channel < LowestChannel || channel > HighestChannel)
        {
            return false;
        }
        CurrentChannel = channel;
        return true;
    }
}

Add a test project

From the folder that holds TvRemote:

dotnet new mstest -n TvRemote.Tests
dotnet add TvRemote.Tests reference TvRemote
dotnet new sln -n TvRemote
dotnet sln add TvRemote TvRemote.Tests
Command Does
dotnet new mstest Makes a test project with the MSTest package
dotnet add ... reference Lets the tests see the app's classes
dotnet new sln, dotnet sln add Puts both projects in one solution, so Visual Studio opens them together

In Visual Studio: right-click the solution in Solution Explorer, Add > New Project..., choose MSTest Test Project, and name it TvRemote.Tests. Then right-click the test project's Dependencies, Add Project Reference..., and check TvRemote.

The test project's .csproj lists the MSTest package, the reference, and one handy line: a global using, so every test file can use MSTest's names without its own using line:

<ItemGroup>
  <PackageReference Include="MSTest" Version="4.0.2" />
</ItemGroup>

<ItemGroup>
  <Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
</ItemGroup>

<ItemGroup>
  <ProjectReference Include="..\TvRemote\TvRemote.csproj" />
</ItemGroup>

(The template also adds Test1.cs, an empty example: delete it.)

Add a test class

Add TelevisionTests.cs to the test project:

namespace TvRemote.Tests;

[TestClass]
public class TelevisionTests
{
    [TestMethod]
    public void ChannelUp_WhenOn_GoesUpOneChannel()
    {
        Television tv = new Television();
        tv.TurnOn();

        int newChannel = tv.ChannelUp();

        Assert.AreEqual(4, newChannel);
    }
}

Two attributes, in square brackets, tell the test runner what to run:

  • [TestClass] marks a class that holds tests.
  • [TestMethod] marks a method that is one test. It's public and returns void. (It takes no parameters, unless it gets them from [DataRow], which Writing Tests shows.)

Methods without [TestMethod] are ordinary helpers: the runner doesn't run them as tests.

Television needs no using: the test class's namespace, TvRemote.Tests, is inside TvRemote, so C# finds TvRemote.Television by itself.

Run it

Run Test > Run All Tests in Visual Studio, or in the terminal:

dotnet test
Passed!  - Failed:     0, Passed:     1, Skipped:     0, Total:     1, Duration: 31 ms - TvRemote.Tests.dll (net10.0)

Test Explorer lists every test with a green check or a red cross. Double-click one to jump to its code, or right-click it to run just that test.

Common problems

What you see What to do
The type or namespace name 'Television' could not be found The test project has no reference to the app. Add it: dotnet add TvRemote.Tests reference TvRemote.
Test Explorer is empty Build the solution (Ctrl+Shift+B) so the runner can find the tests, and check the class has [TestClass].
A test you wrote isn't run It's missing [TestMethod], or it isn't public.

Check yourself

2 questions to try on the lesson page.

So what

One command makes a test project, one more connects it to your app, and two attributes turn a class into tests. From here on, every class you write can have tests beside it.

Key terms

Cheat sheets