.NET C# testing with NUnit and Moq
- Create
HelloMessage
interface andHelloWorldMessage
implementing it in HelloMessage.cs:
public interface HelloMessage
{
public String Text {
get;
}
}
public class HelloWorldMessage : HelloMessage
{
public string Text {
get {
return "Hello World!";
}
}
}
Creating it as an interface will allow us to mock it for testing using Moq which does not support mocking final classes. Maybe other libraries support that but using an interface is simpler.
- Same way create
HelloConsole
interface andHelloSystemConsole
class implementing it in HelloConsole.cs:
public interface HelloConsole {
void Print(String text);
}
public class HelloSystemConsole : HelloConsole
{
public void Print(String text) {
Console.WriteLine(text);
}
}
- Create
HelloApp
in HelloApp.cs:
public class HelloApp
{
private HelloMessage message;
private HelloConsole console;
public HelloApp(HelloMessage message, HelloConsole console) {
this.message = message;
this.console = console;
}
public void PrintHello() {
console.Print(message.Text);
}
}
- Create main Hello.Main/Program.cs that wraps it all together:
var message = new HelloWorldMessage();
var console = new HelloSystemConsole();
var app = new HelloApp(message, console);
app.PrintHello();
Following NUnit > Writing Tests and Moq guides ...
- Test
HelloMessage
in HelloMessageTest.cs:
[Test]
public void ShouldReturnHelloWorld()
{
var message = new HelloWorldMessage();
Assert.That(message.Text, Is.EqualTo("Hello World!"));
}
- Test
HelloApp
in HelloAppTest.cs:
[Test]
public void ShouldPrintHelloMessage()
{
var messageText = "Hello Test!";
// 2.1 Create a mock of HelloMessage
var messageMock = new Mock<HelloMessage>();
// 2.2 Expect HelloMessage mock to receive a call to Text
// and return "Hello Test!"
messageMock.Setup(message => message.Text).Returns(messageText);
// 2.3 Get the mock object to pass it to HelloApp
var message = messageMock.Object;
// 2.4 Create a mock of HelloConsole
var consoleMock = new Mock<HelloConsole>();
// 2.5 No need to set expectations for this one
// 2.6 Get the mock object to pass it to HelloApp
var console = consoleMock.Object;
// 2.3 Create a HelloApp, the one we want to test, passing the mocks
var app = new HelloApp(message, console);
// 2.4 Execute the method we want to test
app.PrintHello();
// 2.5 Verify HelloConsole mock Print() method
// has been called once with "Hello Test!"
consoleMock.Verify(console => console.Print(messageText), Times.Once);
}
- Test output should look like:
NUnit Adapter 4.2.0.0: Test execution complete
Passed ShouldPrintHelloMessage [180 ms]
Passed ShouldReturnHelloWorld [7 ms]
Test Run Successful.
Total tests: 2
Passed: 2
Total time: 2.7702 Seconds
Run this project using 🐳 docker
- Execute
./docker-run.sh
- Once inside the container:
- Test with
dotnet test -v quiet -l:"console;verbosity=normal"
- Run with
dotnet run --project Hello.Main
- Build with
dotnet publish -c Release
- Test with
- Test with
dotnet test -v quiet -l:"console;verbosity=normal"
- Run with
dotnet run --project Hello.Main
- Build with
dotnet publish -c Release
- Execute these commands:
dotnet new sln --name Hello
dotnet new console --language "C#" --framework net8.0 --name Hello.Main
dotnet new nunit --language "C#" --framework net8.0 --name Hello.Test
dotnet add ./Hello.Test reference ./Hello.Main
dotnet add ./Hello.Test package Moq --version 4.20.69
dotnet sln Hello.sln add ./Hello.Main ./Hello.Test