Unit Testing 101: Write your first unit test in C# with MSTest
Do you want to start writing unit tests and you don’t know how to start? Were you asked to write some unit tests on a past interview? Let’s see what a unit test is and how to write your first unit tests in C#.
What is a Unit test?
The book The Art of Unit Testing defines a unit test as “an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work.”
From the previous definition, a unit of work is any logic exposed through public methods. Often, a unit of work returns a value, changes the internals of the system, or makes an external invocation.
If that definition answers how to test public methods, we might ask: ‘What about private methods?’ Short answer: we don’t test them. We test private methods when we call our code through its public methods.
In short, a unit test is code that invokes some code under test and verifies a given behavior of that code.
Why should we write unit tests?
Have you ever needed to change your code, but you were concerned about breaking something? I’ve been there too.
The main reason to write unit tests is to gain confidence. Unit tests allow us to make changes, with confidence that they will work. Unit tests allow change.
Unit tests work like a “safety net” to prevent us from breaking things when we add features or change our codebase.
In addition, unit tests work like living documentation. The first end-user of our code is our unit tests. If we want to know what a library does, we should check its unit tests. Often, we will find non-documented features in the tests.
Your unit tests work like a safety net. Photo by Farzanah Rosli on Unsplash
What makes a good unit test?
Now, we know what a unit test is and why we should write them. The next question we need to answer is: ‘What makes a test a good unit test?’ Let’s see what all good unit tests have in common.
Our tests should run quickly
The longer our tests take to run, the less frequently we run them. And, if we don’t run our tests often, we have doors opened to bugs.
Our tests should run in any order
Tests shouldn’t depend on the output of previous tests to run. A test should create its own state and not rely upon the state of other tests.
Our tests should be deterministic
No matter how many times we run our tests, they should either fail or pass every time. We don’t want our test to use random input, for example.
Our tests should validate themselves
We shouldn’t debug our tests to make sure they passed or failed. Each test should determine the success or failure of the tested behavior. Let’s imagine we have hundreds of tests, and to make sure they pass, we have to debug every one of them. What’s the point, then?
“It could be considered unprofessional to write code without tests” — Robert Martin, The Clean Coder
Let’s write our first unit test with MSTest
Let’s write some unit tests for Stringie, a (fictional) library to manipulate strings with more readable methods.
One of Stringie methods is Remove() . It removes chunks of text from a string. For example, Remove() receives a substring to remove. Otherwise, it returns an empty string if we don’t pass any parameters.
Here’s the implementation of the Remove() method for the scenario without parameters.
Let’s write some tests for the Remove() method. We can write a Console program to test these two scenarios.
However, these aren’t real unit tests. They run quickly, but they don’t run in any order and they don’t validate themselves.
Where should we put our tests?
Let’s create a new project. Let’s add to the solution containing Stringie a new project of type “MSTest Test Project (.NET Core)”. Since we’re adding tests for the Stringie project, let’s name our new test project Stringie.UnitTests.
It’s my recommendation to put our unit tests in a test project named after the project they test. We can add the suffix “Tests” or “UnitTests”. For example, if we have a library called MyLibrary , we should name our test project: MyLibrary.UnitTests .
In our new test project, let’s add a reference to the Stringie project.
Visual Studio Solution Explorer with our new test project
After adding the new test project, Visual Studio created a file UnitTest1.cs . Let’s rename it! We are adding tests for the Remove() method, let’s name this file: RemoveTests.cs .
One way of making our tests easy to find and group is to separate them in files named after the unit of work or entry point of the code we’re testing. Let’s add the suffix “Tests”. For a class MyClass , let’s name our file: MyClassTests .
MSTest
Now, let’s see what’s inside our RemoveTests.cs file.
It contains one normal class and method. However, they’re annotated with two unusual attributes: [TestClass] and [TestMethod] . These attributes tell Visual Studio that our file contains unit tests to run.
The TestClass and TestMethod attributes belong to a project called MSTest. Microsoft Test Framework (MSTest) is an open-source unit testing framework. MSTest comes installed with Visual Studio.
Unit testing frameworks help us to write and run unit tests. Also, they create reports with the results of our tests. Other common unit testing frameworks include NUnit and XUnit.
How should we name our tests?
Let’s replace the name TestMethod1 with a name that follows a naming convention.
We should use naming conventions to show the feature tested and the purpose behind of our tests. Test names should tell what they’re testing.
A name like TestMethod1 doesn’t say anything about the code under test and the expected result.
ItShould
One naming convention for our test names uses a sentence to tell what they’re testing. Often, these names start with the prefix “ItShould” followed by an action. For our Remove() method, it could be:
- ItShouldRemoveASubstring
- ItShouldReturnEmpty
UnitOfWork_Scenario_ExpectedResult
Another convention uses underscores to separate the unit of work, the test scenario, and the expected behavior in our test names. If we follow this convention for our example tests, we name our tests:
- Remove_ASubstring_RemovesThatSubstring
- Remove_NoParameters_ReturnsEmpty
With this convention, we can read our test names out loud like this: “When calling Remove with a substring, then it removes that substring.”
Following the second naming convention, our tests look like this:
These names could look funny at first glance. We should use compact names in our code. However, when writing unit tests, readability is important. Every test should state the scenario under test and the expected result. We shouldn’t worry about long test names.
How should we write our tests? The AAA Principle
Now, let’s write the body of our tests.
To write our tests, let’s follow the Arrange/Act/Assert (AAA) principle. Each test should contain these three parts.
In the Arrange part, we create input values to call the entry point of the code under test.
In the Act part, we call the entry point to trigger the logic being tested.
In the Assert part, we verify the expected behavior of the code under test.
Let’s use the AAA principle to replace one of our examples with a real test. Also, let’s use line breaks to visually separate the AAA parts.
We used the Assert class from MSTest to write the Assert part of our test. This class contains methods like AreEqual() , IsTrue() and IsNull() .
The AreEqual() method checks if the result from a test is equal to an expected value. In our test, we used it to verify the length of the transformed string. We expect it to be zero.
Don’t repeat logic in the assertions
Let’s use a known value in the Assert part instead of repeating the logic under test in the assertions. It’s OK to hardcode some expected values in our tests. We shouldn’t repeat the logic under test in our assertions. For example, we can use well-named constants for our expected values.
Here’s an example of how not to write the Assertion part of our second test.
Notice how it uses the Substring() method in the Assert part to find the string without the Hello substring. A better alternative is to use the expected result in the AreEqual() method.
Let’s rewrite our last test to use an expected value instead of repeating the logic being tested.
How can we run a test inside Visual Studio?
To run a test, let’s right-click on the [TestMethod] attribute of the test and use “Run Test(s)”. Visual Studio will compile your solution and run the test you clicked on.
After the test runs, let’s go to the “Test Explorer” menu. There we will find the list of tests. A passed test has a green icon. If we don’t have the “Test Explorer”, we can use the “View” menu in Visual Studio and click “Test Explorer” to display it.
Test Explorer with our first passing test
That’s a passing test! Hurray!
If the result of a test isn’t what was expected, the Assertion methods will throw an AssertFailedException . This exception or any other unexpected exception flags a test as failed.
MSTest Cheatsheet
These are some of the most common Assertion methods in MSTest.
| Method | Function |
|---|---|
| Assert.AreEqual | Check if the expected value is equal to the found value |
| Assert.AreNotEqual | Check if the expected value isn’t equal to the found value |
| Assert.IsTrue | Check if the found value is true |
| Assert.IsFalse | Check if the found value is false |
| Assert.IsNull | Check if the found value is null |
| Assert.IsNotNull | Check if the found value isn’t null |
| Assert.ThrowsException | Check if a method throws an exception |
| Assert.ThrowsExceptionAsync | Check if an async method throws an exception |
| StringAssert.Contains | Check if a found string contains a substring |
| StringAssert.Matches | Check if a found string matches a regular expression |
| StringAssert.DoesNotMatch | Check if a found string doesn’t match a regular expression |
| CollectionAssert.AreEquivalent | Check if two collections contain the same elements |
| CollectionAssert.AreNotEquivalent | Check if two collections don’t contain the same elements |
| CollectionAssert.Contains | Check if a collection contains an element |
| CollectionAssert.DoesNotContain | Check if a collection doesn’t contain an element |
Conclusion
Voilà! That’s how you write your first unit tests in C# with MSTest. Don’t forget to follow naming conventions and use the Assert class when writing unit tests.
If you want to practice writing more tests for Stringie, check my Unit Testing 101 repository on GitHub.
In this repo, you will find two lessons: one to write some unit tests and another to fix some unit tests.
For more content about unit testing, read 4 common unit testing mistakes and how to name your unit tests. Don’t miss the entire series Unit Testing 101.
Name already in use
visualstudio-docs / docs / test / unit-test-basics.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
23 contributors
Users who have contributed to this file
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Unit test basics
Check that your code is working as expected by creating and running unit tests. It’s called unit testing because you break down the functionality of your program into discrete testable behaviors that you can test as individual units. Visual Studio Test Explorer provides a flexible and efficient way to run your unit tests and view their results in Visual Studio. Visual Studio installs the Microsoft unit testing frameworks for managed and native code. Use a unit testing framework to create unit tests, run them, and report the results of these tests. Rerun unit tests when you make changes to test that your code is still working correctly. Visual Studio Enterprise can do this automatically with Live Unit Testing, which detects tests affected by your code changes and runs them in the background as you type.
Unit testing has the greatest effect on the quality of your code when it’s an integral part of your software development workflow. As soon as you write a function or other block of application code, create unit tests that verify the behavior of the code in response to standard, boundary, and incorrect cases of input data, and that check any explicit or implicit assumptions made by the code. With test driven development, you create the unit tests before you write the code, so you use the unit tests as both design documentation and functional specifications.
Test Explorer can also run third-party and open source unit test frameworks that have implemented Test Explorer add-on interfaces. You can add many of these frameworks through the Visual Studio Extension Manager and the Visual Studio gallery. For more information, see Install third-party unit test frameworks.
You can quickly generate test projects and test methods from your code, or manually create the tests as you need them. When you use IntelliTest to explore .NET code, you can generate test data and a suite of unit tests. For every statement in the code, a test input is generated that will execute that statement. Find out how to generate unit tests for .NET code.
For an introduction to unit testing that takes you directly into coding, see one of these topics:
The Bank solution example
In this article, we use the development of a fictional application called MyBank as an example. You don’t need the actual code to follow the explanations in this topic. Test methods are written in C# and presented by using the Microsoft Unit Testing Framework for Managed Code. However, the concepts are easily transferred to other languages and frameworks.

. moniker range=»vs-2019″ . moniker-end . moniker range=»>=vs-2022″ alt=»MyBank Solution 2022″ width=»» /> . moniker-end
Our first attempt at a design for the MyBank application includes an accounts component that represents an individual account and its transactions with the bank, and a database component that represents the functionality to aggregate and manage the individual accounts.
We create a Bank solution that contains two projects:
Our first attempt at designing the Accounts project contains a class to hold basic information about an account, an interface that specifies the common functionality of any type of account, like depositing and withdrawing assets from the account, and a class derived from the interface that represents a checking account. We begin the Accounts projects by creating the following source files:
AccountInfo.cs defines the basic information for an account.
IAccount.cs defines a standard IAccount interface for an account, including methods to deposit and withdraw assets from an account and to retrieve the account balance.
CheckingAccount.cs contains the CheckingAccount class that implements the IAccount interface for a checking account.
We know from experience that one thing a withdrawal from a checking account must do is to make sure that the amount withdrawn is less than the account balance. So we override the IAccount.Withdraw method in CheckingAccount with a method that checks for this condition. The method might look like this:
Now that we have some code, it’s time for testing.
Create unit test projects and test methods (C#)
For C#, it is often quicker to generate the unit test project and unit test stubs from your code. Or you can choose to create the unit test project and tests manually depending on your requirements. If you want to create unit tests from code with a 3rd party framework you will need one of these extensions installed: NUnit or xUnit. If you are not using C#, skip this section and go to Create the unit test project and unit tests manually.
Generate unit test project and unit test stubs
From the code editor window, right-click and choose Create Unit Tests from the right-click menu.

. moniker range=»vs-2019″
[!NOTE] The Create Unit Tests menu command is only available for C# code. To use this method with .NET Core or .NET Standard, Visual Studio 2019 or later is required. . moniker-end

. moniker range=»>=vs-2022″
[!NOTE] The Create Unit Tests menu command is only available for C# code. To use this method with .NET Core or .NET Standard, Visual Studio 2019 or later is required. . moniker-end
Click OK to accept the defaults to create your unit tests, or change the values used to create and name the unit test project and the unit tests. You can select the code that is added by default to the unit test methods.

. moniker range=»<=vs-2019″ . moniker-end . moniker range=»>=vs-2022″ alt=»Create Unit Tests dialog box in Visual Studio» width=»» /> . moniker-end
The unit test stubs are created in a new unit test project for all the methods in the class.

. moniker range=»vs-2019″ . moniker-end . moniker range=»>=vs-2022″ alt=»The unit tests are created» width=»» /> . moniker-end
Now jump ahead to learn how to Write your tests to make your unit test meaningful, and any extra unit tests that you might want to add to thoroughly test your code.
Create the unit test project and unit tests manually
A unit test project usually mirrors the structure of a single code project. In the MyBank example, you add two unit test projects named AccountsTests and BankDbTests to the Bank solution. The test project names are arbitrary, but adopting a standard naming convention is a good idea.
To add a unit test project to a solution:
In Solution Explorer, right-click on the solution and choose Add > New Project.
Type test in the project template search box to find a unit test project template for the test framework that you want to use. (In the examples in this topic, we use MSTest.)
On the next page, name the project. To test the Accounts project of our example, you could name the project AccountsTests .
In your unit test project, add a reference to the code project under test, in our example to the Accounts project.
To create the reference to the code project:
In the unit test project in Solution Explorer, right-click the References or Dependencies node, and then choose Add Project Reference or Add Reference, whichever is available.
On the Reference Manager dialog box, open the Solution node and choose Projects. Select the code project name and close the dialog box.
Each unit test project contains classes that mirror the names of the classes in the code project. In our example, the AccountsTests project would contain the following classes:
AccountInfoTests class contains the unit test methods for the AccountInfo class in the Accounts project
CheckingAccountTests class contains the unit test methods for CheckingAccount class.
Write your tests
The unit test framework that you use and Visual Studio IntelliSense will guide you through writing the code for your unit tests for a code project. To run in Test Explorer, most frameworks require that you add specific attributes to identify unit test methods. The frameworks also provide a way—usually through assert statements or method attributes—to indicate whether the test method has passed or failed. Other attributes identify optional setup methods that are at class initialization and before each test method and teardown methods that are run after each test method and before the class is destroyed.
The AAA (Arrange, Act, Assert) pattern is a common way of writing unit tests for a method under test.
The Arrange section of a unit test method initializes objects and sets the value of the data that is passed to the method under test.
The Act section invokes the method under test with the arranged parameters.
The Assert section verifies that the action of the method under test behaves as expected. For .NET, methods in the xref:Microsoft.VisualStudio.TestTools.UnitTesting.Assert class are often used for verification.
To test the CheckingAccount.Withdraw method of our example, we can write two tests: one that verifies the standard behavior of the method, and one that verifies that a withdrawal of more than the balance will fail (The following code shows an MSTest unit test, which is supported in .NET.). In the CheckingAccountTests class, we add the following methods:
For more information about the Microsoft unit testing frameworks, see one of the following topics:
Set timeouts for unit tests
If you’re using the MSTest framework, you can use the xref:Microsoft.VisualStudio.TestTools.UnitTesting.TimeoutAttribute to set a timeout on an individual test method:
To set the timeout to the maximum allowed:
Run tests in Test Explorer
When you build the test project, the tests appear in Test Explorer. If Test Explorer is not visible, choose Test on the Visual Studio menu, choose Windows, and then choose Test Explorer (or press Ctrl + E, T).

. moniker range=»vs-2019″ . moniker-end . moniker range=»>=vs-2022″ alt=»Unit Test Explorer» width=»» /> . moniker-end
As you run, write, and rerun your tests, the Test Explorer can display the results in groups of Failed Tests, Passed Tests, Skipped Tests and Not Run Tests. You can choose different group by options in the toolbar.
You can also filter the tests in any view by matching text in the search box at the global level or by selecting one of the pre-defined filters. You can run any selection of the tests at any time. The results of a test run are immediately apparent in the pass/fail bar at the top of the explorer window. Details of a test method result are displayed when you select the test.
Run and view tests
The Test Explorer toolbar helps you discover, organize, and run the tests that you are interested in.
. moniker range=»vs-2019″
. moniker-end . moniker range=»>=vs-2022″
. moniker-end
You can choose Run All to run all your tests (or press Ctrl + R, V), or choose Run to choose a subset of tests to run (Ctrl + R, T). Select a test to view the details of that test in the test details pane. Choose Open Test from the right-click menu (Keyboard: F12) to display the source code for the selected test.
If individual tests have no dependencies that prevent them from being run in any order, turn on parallel test execution in the settings menu of the toolbar. This can noticeably reduce the time taken to run all the tests.
Run tests after every build
To run your unit tests after each local build, open the settings icon in the Test Explorer toolbar and select Run Tests After Build.
Filter and group the test list
When you have a large number of tests, you can type in the Test Explorer search box to filter the list by the specified string. You can restrict your filter event more by choosing from the filter list.
. moniker range=»vs-2019″
. moniker-end . moniker range=»>=vs-2022″
. moniker-end
| Button | Description |
|---|---|
![]() |
To group your tests by category, choose the Group By button. |
Q: How do I debug unit tests?
A: Use Test Explorer to start a debugging session for your tests. Stepping through your code with the Visual Studio debugger seamlessly takes you back and forth between the unit tests and the project under test. To start debugging:
In the Visual Studio editor, set a breakpoint in one or more test methods that you want to debug.
[!NOTE] Because test methods can run in any order, set breakpoints in all the test methods that you want to debug.
In Test Explorer, select the test methods and then choose Debug Selected Tests from the shortcut menu.
Learn more details about debugging unit tests.
Q: If I’m using TDD, how do I generate code from my tests?
A: Use Quick Actions to generate classes and methods in your project code. Write a statement in a test method that calls the class or method that you want to generate, then open the lightbulb that appears under the error. If the call is to a constructor of the new class, choose Generate type from the menu and follow the wizard to insert the class in your code project. If the call is to a method, choose Generate method from the IntelliSense menu.

. moniker range=»vs-2019″ . moniker-end . moniker range=»>=vs-2022″ alt=»Generate Method Stub Quick Action Menu» width=»» /> . moniker-end
Q: Can I create unit tests that take multiple sets of data as input to run the test?
A: Yes. Data-driven test methods let you test a range of values with a single unit test method. Use a DataRow , DynamicData or DataSource attribute for the test method that specifies the data source that contains the variable values that you want to test.
The attributed method runs once for each row in the data source. Test Explorer reports a test failure for the method if any of the iterations fail. The test results detail pane for the method shows you the pass/fail status method for each row of data.
Q: Can I view how much of my code is tested by my unit tests?
A: Yes. You can determine the amount of your code that is actually being tested by your unit tests by using the Visual Studio code coverage tool in Visual Studio Enterprise. Native and managed languages and all unit test frameworks that can be run by the Unit Test Framework are supported.
You can run code coverage on selected tests or on all tests in a solution. The Code Coverage Results window displays the percentage of the blocks of product code that were exercised by line, function, class, namespace and module.
To run code coverage for test methods in a solution, choose Test > Analyze Code Coverage for All Tests.
Coverage results appear in the Code Coverage Results window.
. moniker range=»<=vs-2019″
. moniker-end . moniker range=»>=vs-2022″
. moniker-end
Q: Can I test methods in my code that have external dependencies?
A: Yes. If you have Visual Studio Enterprise, Microsoft Fakes can be used with test methods that you write by using unit test frameworks for managed code.
Microsoft Fakes uses two approaches to create substitute classes for external dependencies:
Stubs generate substitute classes derived from the parent interface of the target dependency class. Stub methods can be substituted for public virtual methods of the target class.
Shims use runtime instrumentation to divert calls to a target method to a substitute shim method for non-virtual methods.
In both approaches, you use the generated delegates of calls to the dependency method to specify the behavior that you want in the test method.
Q: Can I use other unit test frameworks to create unit tests?
A: Yes, follow these steps to find and install other frameworks. After you restart Visual Studio, reopen your solution to create your unit tests, and then select your installed frameworks here:
Как сделать тест на наличие COVID-19 в домашних условиях – 10 шагов
На фармацевтический рынок Республики Молдова поступил новый тип экспресс-теста на коронавирус. COVID-19 Antigen Rapid Test Kit уже доступен во всех аптеках и стоит 140 леев. Согласно данным производителя, точность теста – 98,5%, тест также чувствителен ко всем известным штаммам, а результат выявляется меньше чем за 15 минут. Набор для тестирования включает стерильную палочку, пробирку для экстракции, раствор для лизиса, тестовый контейнер и подробную инструкцию для эксплуатации. Тест можно сделать самостоятельно в домашних условиях.
Введение в модульное тестирование для c# проектов в среде MonoDevelop
Почему был выбран C#? Это довольно легкий в освоении язык программирования. В котором не нужно задумываться над выделением памяти и её очисткой. Широкий выбор различных библиотек .NET позволяет без особого труда реализовать сложные задачи. Помимо этого, программы скомпилированные в одной платформе с использованием CLR можно запустить на другой платформе, в которой присутствует реализация CLR.
Создание программы HelloWorld
- Запустите MonoDevelop и создайте новый проект HelloWorld.

- Создайте новый класс Goodbyer.

- Помимо конструктора без параметров, создайте конструктор со строкой, в качестве параметра. А так же метод, возвращающий строку и позволяющий задавать значение поля _who.
Создание модульных тестов
- Создайте новый проект библиотеки тестов NUnit в данном решении.

- Добавьте ссылку на проект HelloWorld.

- Создайте несколько модульных тестов для конструктора с параметрами и для метода задающего значение поля _who. Картинка 5
- На следующем изображении видно, что не все тесты были пройдены. Так как программа не выдает исключения, когда мы задаем поле _who пустым.

Изменение класса Goodbyer для прохождения модульных тестов
- Изменим класс Goodbyer так, чтобы он выдавал исключения, когда в поле _who записывается пустая строка.

- На вышестоящем изображении видно, что все тесты были пройдены.
На этом все. Если вы проделали все шаги, то вас можно поздравить с освоением простейших принципов модульного тестирования.
