Would it be possible to test a function with returns void and only writes a line to the console like the following using FluentAssertion
?
static void WriteLine()
{
Console.WriteLine("It works!");
}
Would it be possible to test a function with returns void and only writes a line to the console like the following using FluentAssertion
?
static void WriteLine()
{
Console.WriteLine("It works!");
}
If you want to unit test things like this, you need to extract into an interface the methods(s) you want to verify the calling of.
Then you pass that interface to the classes that need to use it, rather than having the classes call the implementation (in this case, Console.WriteLine()
) directly. This is called "dependency injection".
So for your example, you'd invent the following interface:
public interface IConsole
{
void WriteLine(string text);
}
Your real code would be passed an instance of the following concrete implementation of IConsole
:
public sealed class MyConsole : IConsole
{
public void WriteLine(string text)
{
Console.WriteLine(text);
}
}
However, when testing your class you would pass it a special test implementation of IConsole
.
Let's suppose you have the following class that uses the IConsole
interface:
public class UnderTest
{
public UnderTest(IConsole console)
{
_console = console;
}
public void WriteLine()
{
_console.WriteLine("It works!");
}
readonly IConsole _console;
}
Note how the IConsole
is passed to the constructor - this is known as "constructor injection".
Now, you want to test that when you call UnderTest.WriteLine()
it calls IConsole.WriteLine("It works!");
.
To do this, firstly use a mocking framework such as Moq to mock the IConsole
interface:
var mock = new Mock<IConsole>();
Then construct an instance of the class you want to test, passing to it the mocked IConsole
:
var underTest = new UnderTest(mock.Object);
Now you can call the method that you expect to call IConsole.WriteLine("It works!")
:
underTest.WriteLine();
Finally you can verify that IConsole.WriteLine("It works!")
was called:
mock.Verify(x => x.WriteLine("It works!"));
Putting this all together into a single console app:
using System;
using Moq;
namespace Demo
{
public interface IConsole
{
void WriteLine(string text);
}
// Not used but included as an example implementation.
public sealed class MyConsole : IConsole
{
public void WriteLine(string text)
{
Console.WriteLine(text);
}
}
public class UnderTest
{
public UnderTest(IConsole console)
{
_console = console;
}
public void WriteLine()
{
_console.WriteLine("It works!");
}
readonly IConsole _console;
}
public class Program
{
public static void Main()
{
var mock = new Mock<IConsole>();
var underTest = new UnderTest(mock.Object);
underTest.WriteLine();
mock.Verify(x => x.WriteLine("It works!"));
}
}
}
(Note that to compile this you will need to install Moq.)
I didn't use FluentAssertions
with this example, but you can use them alongside Moq
as much or as little as you like.
You should not have a function that writes a line to the console.
You should have a function that writes a line to a System.IO.TextWriter
passed to it as a parameter.
From production code, you pass this function a reference to System.Console.Out
, so it behaves like "a function that writes a line to the console".
From testing code, you pass it an instance of System.IO.StringWriter
, so you can examine what it writes to it.
This is an application of the very well known concept of Dependency Injection, and it is absolutely essential for writing testable code. Use it in everything you do.
Wikipedia: Dependency injection
You can achieve this by monitoring standard output (it's the OS level stream that handles all software output).
If you implemented something like the example here and monitored the latest output, you could then use an assertion on those top messages to determine if your application is performing properly.