Unit testing Visual Basic .NET Core libraries using dotnet test and MSTest
This tutorial takes you through an interactive experience building a sample solution step-by-step to learn unit testing concepts. If you prefer to follow the tutorial using a pre-built solution, view or download the sample code before you begin. For download instructions, see Samples and Tutorials.
This article is about testing a .NET Core project. If you're testing an ASP.NET Core project, see Integration tests in ASP.NET Core.
Creating the source project
Open a shell window. Create a directory called unit-testing-vb-mstest to hold the solution.
Inside this new directory, run dotnet new sln
to create a new solution. This practice
makes it easier to manage both the class library and the unit test project.
Inside the solution directory, create a PrimeService directory. You have the following directory and file structure thus far:
/unit-testing-vb-mstest
unit-testing-vb-mstest.sln
/PrimeService
Make PrimeService the current directory and run dotnet new classlib -lang VB
to create the source project. Rename Class1.VB to PrimeService.VB. You create a failing implementation of the PrimeService
class:
Namespace Prime.Services
Public Class PrimeService
Public Function IsPrime(candidate As Integer) As Boolean
Throw New NotImplementedException("Please create a test first")
End Function
End Class
End Namespace
Change the directory back to the unit-testing-vb-using-mstest directory. Run dotnet sln add .\PrimeService\PrimeService.vbproj
to add the class library project to the solution.
Creating the test project
Next, create the PrimeService.Tests directory. The following outline shows the directory structure:
/unit-testing-vb-mstest
unit-testing-vb-mstest.sln
/PrimeService
Source Files
PrimeService.vbproj
/PrimeService.Tests
Make the PrimeService.Tests directory the current directory and create a new project using dotnet new mstest -lang VB
. This command creates a test project that uses MSTest as the test library. The generated template configures the test runner in the PrimeServiceTests.vbproj:
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.1.18" />
<PackageReference Include="MSTest.TestFramework" Version="1.1.18" />
</ItemGroup>
The test project requires other packages to create and run unit tests. dotnet new
in the previous step added MSTest and the MSTest runner. Now, add the PrimeService
class library as another dependency to the project. Use the dotnet add reference
command:
dotnet add reference ../PrimeService/PrimeService.vbproj
You can see the entire file in the samples repository on GitHub.
You have the following final solution layout:
/unit-testing-vb-mstest
unit-testing-vb-mstest.sln
/PrimeService
Source Files
PrimeService.vbproj
/PrimeService.Tests
Test Source Files
PrimeServiceTests.vbproj
Execute dotnet sln add .\PrimeService.Tests\PrimeService.Tests.vbproj
in the unit-testing-vb-mstest directory.
Creating the first test
You write one failing test, make it pass, then repeat the process. Remove UnitTest1.vb from the PrimeService.Tests directory and create a new Visual Basic file named PrimeService_IsPrimeShould.VB. Add the following code:
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Namespace PrimeService.Tests
<TestClass>
Public Class PrimeService_IsPrimeShould
Private _primeService As Prime.Services.PrimeService = New Prime.Services.PrimeService()
<TestMethod>
Sub IsPrime_InputIs1_ReturnFalse()
Dim result As Boolean = _primeService.IsPrime(1)
Assert.IsFalse(result, "1 should not be prime")
End Sub
End Class
End Namespace
The <TestClass>
attribute indicates a class that contains tests. The <TestMethod>
attribute denotes a method that is run by the test runner. From the unit-testing-vb-mstest, execute dotnet test
to build the tests and the class library and then run the tests. The MSTest test runner contains the program entry point to run your tests. dotnet test
starts the test runner using the unit test project you've created.
Your test fails. You haven't created the implementation yet. Make this test pass by writing the simplest code in the PrimeService
class that works:
Public Function IsPrime(candidate As Integer) As Boolean
If candidate = 1 Then
Return False
End If
Throw New NotImplementedException("Please create a test first.")
End Function
In the unit-testing-vb-mstest directory, run dotnet test
again. The dotnet test
command runs a build for the PrimeService
project and then for the PrimeService.Tests
project. After building both projects, it runs this single test. It passes.
Adding more features
Now that you've made one test pass, it's time to write more. There are a few other simple cases for prime numbers: 0, -1. You could add those cases as new tests with the <TestMethod>
attribute, but that quickly becomes tedious. There are other MSTest attributes that enable you to write a suite of similar tests. A <DataTestMethod>
attribute represents a suite of tests that execute the same code but have different input arguments. You can use the <DataRow>
attribute to specify values for those inputs.
Instead of creating new tests, apply these two attributes to create a single theory. The theory is a method that tests several values less than two, which is the lowest prime number:
<TestClass>
Public Class PrimeService_IsPrimeShould
Private _primeService As Prime.Services.PrimeService = New Prime.Services.PrimeService()
<DataTestMethod>
<DataRow(-1)>
<DataRow(0)>
<DataRow(1)>
Sub IsPrime_ValuesLessThan2_ReturnFalse(value As Integer)
Dim result As Boolean = _primeService.IsPrime(value)
Assert.IsFalse(result, $"{value} should not be prime")
End Sub
<DataTestMethod>
<DataRow(2)>
<DataRow(3)>
<DataRow(5)>
<DataRow(7)>
Public Sub IsPrime_PrimesLessThan10_ReturnTrue(value As Integer)
Dim result As Boolean = _primeService.IsPrime(value)
Assert.IsTrue(result, $"{value} should be prime")
End Sub
<DataTestMethod>
<DataRow(4)>
<DataRow(6)>
<DataRow(8)>
<DataRow(9)>
Public Sub IsPrime_NonPrimesLessThan10_ReturnFalse(value As Integer)
Dim result As Boolean = _primeService.IsPrime(value)
Assert.IsFalse(result, $"{value} should not be prime")
End Sub
End Class
Run dotnet test
, and two of these tests fail. To make all of the tests pass, change the if
clause at the beginning of the method:
if candidate < 2
Continue to iterate by adding more tests, more theories, and more code in the main library. You have the finished version of the tests and the complete implementation of the library.
You've built a small library and a set of unit tests for that library. You've structured the solution so that adding new packages and tests is part of the normal workflow. You've concentrated most of your time and effort on solving the goals of the application.