Sending Messages at Scale – Cannot allocate more handles

When sending many messages (thousands or tens of thousands) you may find that you run into errors that you may not see while testing with lower numbers of messages. One such error that I’ve encountered recently is this:

Azure.Messaging.ServiceBus.ServiceBusException: ‘Cannot allocate more handles. The maximum number of handles is 4999. (QuotaExceeded)’

Some code to replicate the issue:

for (int i = 1; i <= 10000; i++)
{
    var sender = serviceBusClient.CreateSender("topic-name");

    string messageText = $"Test{i}--{DateTime.Now.ToString("yy-MM-dd")}";
    var msg = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageText));
    await sender.SendMessageAsync(msg);
}    

There is a limit on concurrent connections to the service bus, set at 4,999 at the time of writing; that is, you cannot have 5,000 connections at the same time. Every time a call to CreateSender is called, a new connection is made to the service bus. Because this is a tight loop, the connections cannot be cleaned up in time, and so it overwhelms the service.

There are three mechanisms for avoiding this. By far the best and easiest is to send the messages as a batch.

Sending Messages as a Batch

List<ServiceBusMessage> serviceBusMessages = new();    
for (int i = 1; i <= 10000; i++)
{
    string messageText = $"Test{i}--{DateTime.Now.ToString("yy-MM-dd")}";
    serviceBusMessages.Add(
       new ServiceBusMessage(Encoding.UTF8.GetBytes(messageText)));        
}
await sender.SendMessagesAsync(serviceBusMessages);

This is far faster, and avoids 10,000 calls to the service. The caveat here is the size of the message – if the 10,000 messages exceed a single message size, then it may be necessary to batch the messages into groups of 1000, or even 100 – depending on the size of each message.

Cleaning up the Client

This mechanism is to forcibly dispose of the message factory each loop:

for (int i = 1; i <= count; i++)
{
    var sender = serviceBusClient.CreateSender("topic-name");

    string messageText = $"Test{i}--{DateTime.Now.ToString("yy-MM-dd")}";
    var msg = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageText));
    await sender.SendMessageAsync(msg);

    await sender.CloseAsync();
}    

Change the Scope of the Message Factory

The final method is to simply move the creation of the message factory outside the loop:

    var sender = serviceBusClient.CreateSender("topic-name");
    for (int i = 1; i <= count; i++)
    {
        string messageText = $"Test{i}--{DateTime.Now.ToString("yy-MM-dd")}";
        var msg = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageText));
        await sender.SendMessageAsync(msg);

    }    

Summary

If you’re dealing with large quantities of messages, then the batch send is by far the best option, as it not only avoids the issue with too many handles, but speeds up the whole process.

ServiceBusAdministrationClient Update Lock Duration Not Working

When you start to experiment with very large messages, or very large quantities of messages, there are times when the default lock duration of 30 seconds for Azure Service Bus can cause issues. In this post, I’ll show how this can be changed at a subscription or queue level using the Azure.Messaging.ServiceBus client.

Caveat

As with previous articles that I’ve written on Service Bus, I’m not advocating this as a desirable way to deal with such cases; however, times do arise when it makes sense to adjust this value.

The Code

The key here is the ServiceBusAdministrationClient. It allows you to get a reference to the subscription or queue:

    var serviceBusAdministrationClient = new ServiceBusAdministrationClient(connectionString);
    var sub = await serviceBusAdministrationClient.GetSubscriptionAsync("topic", "sub1");

You can then change something on that object; for example:

sub.Value.LockDuration = TimeSpan.FromSeconds(newDuration);

But it’s not updating

Somewhat counter intuitively, the final step is to update with the new object:

await serviceBusAdministrationClient.UpdateSubscriptionAsync(sub);

The subscription / queue should then update fine.

Summary

In this post, we’ve discussed how you can change the lock duration using the Azure Service Bus SDK. We’ve also shown how easy it can be to not realise that you need to explicitly update (ask me how I know!)

Compressing a Service Bus Message Using Gzip

I’ve recently been playing around at the edges of Azure Service Bus. One of the things that occurred to me was that, for a large message, you could improve speed and save money by simply compressing the message before sending.

The obvious downside to this approach is that your consumer needs to be aware that the message is compressed. The other issue is that there is an overhead to compression and decompression, both in size and in speed, so compressing a small message is pointless (or worse – it may actually increase the size and time to transmit).

That’s the why and why not, let’s move onto the how.

How to Send a Compressed Message

Let’s start with a re-cap on how to send a message without it being compressed:

async Task SendMessage(string connectionString, string topicName, string messageText)
{
    await using var serviceBusClient = new ServiceBusClient(connectionString);
    var sender = serviceBusClient.CreateSender(topicName);
    
    var message = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageText));

    await sender.SendMessageAsync(message);
}

Since this sends a message, which is just a stream of text, all we need to do now is compress that message. An easy way is to use GZipStream:

byte[] CompressBytes(byte[] bytes)
{    
    using var memoryStream = new MemoryStream();
    using var gzipStream = new GZipStream(memoryStream, CompressionLevel.SmallestSize);
    gzipStream.Write(bytes, 0, bytes.Length);
    gzipStream.Close();

    return memoryStream.ToArray();
}

This method takes an array of bytes, and runs them through the GZipStream to apply the Gzip compression algorithm on it. All we now need to do is to convert our string to a byte array – we can use something like the following, which also converts the resulting string to Base64 – meaning we can transport it easier:

string CompressMessage(string toCompress)
{
    var bytes = Encoding.UTF8.GetBytes(toCompress);

    var returnBytes = CompressBytes(bytes);

    string returnValue = Convert.ToBase64String(returnBytes);
    return returnValue;
}

We now have all the building blocks, we can simply assemble them in the correct order:

var compressed = CompressMessage(largeMessage);
await SendMessage(connectionString, "compressed-message", compressed);

All that’s left is to receive the message.

How to Receive a Compressed Message

Again, let’s start with a basic method to receive the next message on the service bus:

async Task<string> ConsumeNextMessage(string topic)
{
    await using var serviceBusClient = new ServiceBusClient(connectionString);
    var receiver = serviceBusClient.CreateReceiver(topic, "sub-1");
    var message = await receiver.ReceiveMessageAsync();
    return message.Body.ToString();
}

This will simply read the next message for the given subscription and return its contents. As with the send, we simply need the other building blocks; we’ll start with decompressing the bytes:

byte[] DecompressBytes(byte[] bytes)
{    
    using var memoryStream = new MemoryStream(bytes);
    using var outputStream = new MemoryStream();
    using var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress);
    decompressStream.CopyTo(outputStream);
    var returnBytes = outputStream.ToArray();
    return returnBytes;
}

Again, we’re using GZipStream to return a decompressed version of the data. We’ll call that in the same manner as above:

string DecompressMessage(string compressed)
{
    var bytes = Convert.FromBase64String(compressed);
    
    var returnBytes = DecompressBytes(bytes);
    return Encoding.UTF8.GetString(returnBytes);
}

It’s worth remembering that we’re transporting the compressed data using Base64, so we need to convert it from that first. Finally, we can assemble the methods:

var message = await ConsumeNextMessage("compressed-message");
var decompressed = DecompressMessage(message);

What difference does it make?

Is it really worth all this message around? The answer is probably an emphatic no. However, in a very small subset of cases, this might mean that you can continue on the standard tier, rather than upgrade to premium.

This also helps with speed – sending a 70MB message takes around 50 – 55 seconds in my tests. The same message compressed was around 5MB and took only 5 seconds to send.

References

https://docs.microsoft.com/en-us/dotnet/api/system.io.compression.gzipstream?view=net-6.0

https://www.infoworld.com/article/3660629/how-to-compress-and-decompress-strings-in-c-sharp.html

Transmitting an Image via Azure Service Bus

This post in a continuation of this earlier post around serialising an image. Once you’re able to serialise an image, then you can transmit that image. In this post, we’ll see how we could do that using Azure Service Bus.

A Recap on Image Serialisation

In the previous (linked) post, we saw how we can turn an image into a string of text, and back again. Essentially, what we did was use a BinaryWriter to write the file as a binary stream, and a BinaryReader to turn it back to an image.

The plan here is to do exactly the same thing, but to simply write the stream to an Azure Service Bus Message, and read from it at the other side.

Size Matters

One thing that you’re going to need to be aware of here is the size of the image. The free tier of Service Bus limits you to 256KB. Serialising an image to stream can be less than that, but unless you know different, you should assume that it will be bigger. Even after you sign up for the much more expensive premium tier, when you set-up the topic or queue, you’ll need to specify a maximum size. Images can be very big!

Alternatives

To be clear: the purpose of this post is to demonstrate that you can transmit an image via Service Bus – not that you should. There are other ways to do this: for example, you could upload the image to blob storage, or an S3 bucket, and then just point to that in the message. The one advantage transmitting the image with the message does give you, is that the binary data lives and dies with the message itself – so depending on what you do with the message after receipt, that may be an advantage.

Transmitting the Message

The following is a simple helper method that will send the message for us:

async Task SendMessage(string connectionString, string topicName, string messageText)
{    
    int byteCount = System.Text.ASCIIEncoding.ASCII.GetByteCount(messageText);

    await using var serviceBusClient = new ServiceBusClient(connectionString);
    var sender = serviceBusClient.CreateSender(topicName);
    
    var message = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageText));

    await sender.SendMessageAsync(message);
}

byteCount tells you how big the message is going to be. Useful when you’re writing a blog post about such things, but you may find it useful for debugging.

The rest is pretty basic Azure Service Bus SDK stuff. I’ve written about this previously in more depth.

We can then combine this with the code from the last post:

        var serialisedToSend = SerialiseImageToBinary(
            @"c:\tmp\myimage.png");
        await SendLargeMessage(connectionString, "image-message", serialisedToSend);

The next step is to receive the message at the other side.

Consuming the Message

As with the send, we have a helper method here:

async Task<string> ConsumeNextMessage(string topic)
{
    var serviceBusClient = new ServiceBusClient(connectionString);
    var receiver = serviceBusClient.CreateReceiver(topic, "sub-1");
    var message = await receiver.ReceiveMessageAsync();
    return message.Body.ToString();
}

Again, I’ve written about receiving a message using the SDK before.

Here, we do the reverse of the send:

        var serialisedToReceive = await ConsumeNextMessage("image-message");

        DeserialiseImageFromBinary(
            serialisedToReceive,
            @$"c:\tmp\newimg{DateTime.Now.ToString("yy-MM-dd-HH-mm-ss")}.png");

I’ve used the date so that I could test this multiple times – other than that, we’re receiving the serialised image, and then writing it to disk.

Summary

I’ll re-iterate the sentiment that I’m not advocating this as a good or preferable way to transmit images, simply highlighting that it is possible with relatively little work.

Serialising and De-serialising Images

For another project that I’m working on, I needed to transfer an image as text. In fact, that’s actually quite an easy thing to do in .Net. The way is to use a BinaryWriter and BinaryReader.

Binary Serialisation Helpers

The first step is to create a helper to serialise or de-serialise anything to or from binary. We’ll start with Serialise:

string SerialiseToBinary<TData>(TData data)
{
    string serialised = JsonSerializer.Serialize(data);

    using var stream = new MemoryStream();
    using var binary = new BinaryWriter(stream);
    binary.Write(serialised);

    stream.Flush();
    stream.Position = 0;
    return Convert.ToBase64String(stream.ToArray());
}

We start by simply calling the JSON serialise method – that way, anything that’s passed in is now a string. Then we need a stream to write to – in fact, you could do this directly to a file, but here we’re just using a memory stream. Finally we convert to Base64 (Conversion to Base 64 isn’t strictly necessary for this, but if you want to send the binary data anywhere afterwards then it may be).

Next is the Deserialise method:

TData? DeserialiseFromBinary<TData>(string data)
{
    byte[] b = Convert.FromBase64String(data);
    using var stream = new MemoryStream(b);
    using var br = new BinaryReader(stream);

    stream.Seek(0, SeekOrigin.Begin);
    var resultString = br.ReadString();
    var result = JsonSerializer.Deserialize<TData>(resultString);
    return result;
}

Here we’re converting from Base 64 – which obviously is necessary if you’ve encoded with it on the other side. Then we have the same in reverse – using the binary reader to read the memory stream, and then de-serialise the result.

Writing and Reading from Files

Now that we can write and read binary data, we can add a couple of other helpers to do this from a file – for this experiment, I’m simply copying an image:

string SerialiseImageToBinary(string path)
{
    var bytes = File.ReadAllBytes(path);
    var serialised = SerialiseToBinary(bytes);
    return serialised;
}

void DeserialiseImageFromBinary(string data, string outPath)
{    
    var deserialised = DeserialiseFromBinary<byte[]>(data);
    using var fs = new FileStream(outPath, FileMode.CreateNew);
    fs.Write(deserialised);    
}

Probably not worth going into too much detail on these methods: they simply read and write from files, calling our other helper methods. I then call them like this:

        var serialised = SerialiseImageToBinary(
            @"c:\tmp\testimg.png");
        Console.WriteLine(serialised);

        DeserialiseImageFromBinary(
            serialised,
            @"c:\tmp\testimg2.png");

I’ll be coming back to these methods in future posts around transmitting this information over Azure Service Bus.

Listing all topics and subscriptions in an Azure Service Bus Namespace

For anyone that follows this blog, you’ll notice that Azure Service Bus is one of my favourite topics. In this post, we’re going to see how you can list all subscriptions to all topics within a namespace.

var serviceBusClient = new ServiceBusClient(connectionString);

var serviceBusAdminClient = new ServiceBusAdministrationClient(connectionString);
var topics = serviceBusAdminClient.GetTopicsAsync();
await foreach (var topic in topics)
{
    var subs = serviceBusAdminClient.GetSubscriptionsAsync(topic.Name);
    await foreach (var sub in subs)
    {
        Console.WriteLine($"{sub.TopicName}: {sub.SubscriptionName}");
    }
}

We’re using the latest service bus library, and the ServiceBusAdministrationClient, which lets us traverse the topics, and the subscriptions within them.

References

https://www.pmichaels.net/2021/06/26/receiving-a-message-using-azure-messaging-servicebus/

Introduction to Unit Tests (with examples in .Net) – Part 4 – Mocking (Including fakes and stubs)

In this, forth (and probably final) post on the subject of Unit Tests, we’re going to dive a little deeper into the subject of mocking. We’ll discuss what the difference is between a mock, a stub, and a fake; we’ll also talk about mocking frameworks.

A Fake, Stubby, Mock

These terms are often used interchangeably, and that’s fine – but they can mean different things. There are a couple of sources (that I could find) that have defined the difference between these terms:

Mocks Aren’t Stubs – an article from 2007 by Martin Fowler.

xUnit Test Patterns – a book on Unit Testing.

Broadly, they both say the same, which is this:

A Stub is a replacement for functionality that will return a given value without actually executing any life-like code.

A Mock is similar to a stub, but allows for analysis of that behaviour – for example, you can determine whether or not the method was called, or how many times.

A Fake is a replacement for functionality that is intended to mimic the actual functionality of the code.

A Test Double is a generic term to encompass all three.

Let’s have a look at an example for each. We’ll stick with manual test doubles for now. Let’s consider one of the manual mocks that we created in the last post:

    public class MockInputOutputWrapper : IInputOutputWrapper
    {
        private readonly string _inputValue;

        public MockInputOutputWrapper(string inputValue) =>
            _inputValue = inputValue;        

        public string GetInput(string prompt) => _inputValue;        

        public void Output(string text) { }
    }

Stub

Our first call is the stub, which is the Output method in the code above. It provides a method to call, but no functionality whatsoever.

Mock

Let’s imagine that we wanted to ascertain how many times we called Output – we may do something like this:

public class MockInputOutputWrapper : IInputOutputWrapper
{
    private readonly string _inputValue;
    private int _outputCount = 0;

    public MockInputOutputWrapper(string inputValue) =>
        _inputValue = inputValue;        

    public string GetInput(string prompt) => _inputValue;        

    public void OutputCallsMustBe(int count)
    {
        if (count != _outputCount) throw new Exception("Output Calls Incorrect");
    }

    public void Output(string text) 
    {
        _outputCount++;
    }
}

Now Output is a mock, rather than a stub. For this post, I won’t go to the extent of writing a mocking framework, but I think the code above illustrates the point. That is, we can ascertain that Output has been called, say, once:

[Fact]
public void Output_ValidGuess_CalledOnce()
{
    // Arrange
    var inputOutputWrapper = new MockInputOutputWrapper("12");
    var randomNumberChooser = new MockRandomNumberChooser();
    var sut = new Game(inputOutputWrapper, randomNumberChooser);

    // Act
    string result = sut.RunMethod();

    // Assert
    Assert.Equal("Well done, you guessed!", result);
    inputOutputWrapper.OutputCallsMustBe(1);
}

Finally, we’ll discuss what a fake is.

Fake

Fakes allow for functionality to be replicated in a way that’s more conducive to the test. The stub allowed us to essentially ignore the functionality altogether; the mock allowed us to assert that, despite replacing the functionality, it had actually been invoked (or would have been); the fake allows us to substitute that functionality. A good example here is a database – in order to test the interaction with a database, you may find it necessary to actually store some data in memory. Using our example, what if we needed to ascertain that the game dealt with different random numbers; we could write this:

[Fact]
public class MockRandomNumberChooser : IRandomNumberChooser
{
    private int[] _numberList = new[] { 12, 3, 43 };
    private int _index = 0;
    public int Choose() => _numberList[_index++];
}

Now that we understand the difference, we’ll see that it can be very academic, especially when dealing with mocking frameworks.

There’s a lot of boiler plate code here. Manually creating these classes does the job, but imagine the following scenario: you have 5 different mock classes, and you add a method to the interface IRandomNumberChooser. You now need to manually go through each of those mocks and add the functionality necessary to mock out the new function – you are very likely to not care about the new function in most of those methods, but nevertheless, you would need to go and honour the interface.

Mocking Frameworks

Mocking frameworks aim to solve this problem by creating a mechanism to mock or subclass an object. There are currently two main mocking frameworks for .Net: Nsubstitute and Moq. There’s also Microsoft Fakes.

We won’t cover all of these, and the principle behind them is broadly the same, with a slightly different implementation bias. I’ve always found NSubstitute much more intuitive, so we’ll cover that.

We’ll start by simply deleting the MockRandomNumberChooser. Now install Nsubstitute:

Install-Package NSubstitute

The next part is to simply tell NSubstitute to do the same thing that you had done using the mock class:

var randomNumberChooser = Substitute.For<IRandomNumberChooser>();
randomNumberChooser.Choose().Returns(12);

If you run the test, you’ll see absolutely no difference. Based on our discussion earlier in the post, we have created a stub, but we can create both Mocks and Fakes using the same class. If you want to create a mock, you’ll do so like this:

randomNumberChooser.Received(1).Choose();

Fakes are a little different, however, you can still replace the functionality.

References

https://www.pmichaels.net/2018/03/22/using-nsubstitute-for-partial-mocks/

https://github.com/nsubstitute/NSubstitute/

https://github.com/moq

WireMock.Net

I was recently introduced to the WireMock.Net package. This is a .Net implementation of WireMock.

The basic idea where is that you can mock or stub a HTTP call. For example, you can tell it that when https://localhost:1234/test is called then a specific response should be returned – you could, for example, force it to error.

To get started, install the package:

install-package wiremock.net

This is a hefty package, so make sure it’s restricted to your test project.

The following code will replace the URL above with a response of “aaa”:

using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;

Console.WriteLine("Hello, World!");


var request = Request.Create()    
    .WithPath("/test")
    .UsingGet();

var response = Response.Create()
    .WithStatusCode(200)
    .WithBody("aaa");

WireMockServer wireMockServer = WireMockServer.Start(1234);
wireMockServer
    .Given(request)
    .RespondWith(response);


HttpClient client = new HttpClient();
var result = await client.GetAsync("http://localhost:1234/test");
if (result != null && result.IsSuccessStatusCode)
{
    var output = await result.Content.ReadAsStringAsync();
    Console.WriteLine(output);
}

I did, at first, try to run this for an actual site (e.g. to intercept google.com or something), but it won’t allow that, only localhost (at least, as far as I could see). A friend at work pointed out that, in a test, you would pass the URL in through the config anyway, and so you could change it to localhost.

References

https://pcholko.com/posts/2021-04-05/wiremock-integration-test/

Introduction to Unit Tests (with examples in .Net) – Part 3 – Test Frameworks and Manual Mocks

So far, in this series of posts on the basics of unit tests, we’ve spoken about concepts and methodologies, but we’ve steered away from using any specific frameworks or tools. In this post, we’ll investigate what a test framework can do for us.

We’ll continue to work with the code that we created in the previous post, but we’ll address the issues that we still had at the end of that post.

A Recap of the Story So Far

At the end of the previous post, we had the following code:

for (int i = 1; i <= 100; i++)
{
    // Arrange
    Func<string> mockInput = () => "5";
 
    // Act
    string result = RunMethod(mockInput);
 
    // Assert
    if (result == "Well done, you guessed!")
    {
        Console.WriteLine("Test Passed");
        break;
    }
}
 
for (int i = 1; i <= 100; i++)
{
    // Arrange
    Func<string> mockInput = () => "5";
 
    // Act
    string result = RunMethod(mockInput);
 
    // Assert
    if (result.StartsWith("Sorry, that was the wrong number"))
    {
        Console.WriteLine("Test Passed");
        break;
    }
}
 
{
    // Arrange
    Func<string> mockInput = () => "";
 
    // Act
    string result = RunMethod(mockInput);
 
    // Assert
    if (result == "Invalid guess")
    {
        Console.WriteLine("Test Passed");
    }
}

We had yet to introduce any tools or frameworks, but we had managed to test our code. We still had the following issues, however:

1. The tests passed, but we visually have to visually ascertain that.
2. We were outputting to the console needlessly.
3. Our tests were not resilient – a change of a single character in the user output, and the tests would break.
4. The tests were not deterministic – they were dependent on the result of a pseudo random number.

In this post, we’ll address these issues in order (apart from the third one, but we’ll come back to that) : we’ll start with the first.

1. The tests passed, but we visually have to visually ascertain that

How can we ascertain the result of a test without watching to see what happens with the test. One thing we could do is something similar to the following:

int RunTest1()
{
    for (int i = 1; i <= 100; i++)
    {
        // Arrange
        Func<string> mockInput = () => "5";

        // Act
        string result = RunMethod2(mockInput);

        // Assert
        if (result == "Well done, you guessed!")
        {
            Console.WriteLine("Test Passed");
            return 0;
        }
    }
    return 1;
}

int RunTest2()
{
    for (int i = 1; i <= 100; i++)
    {
        // Arrange
        Func<string> mockInput = () => "5";

        // Act
        string result = RunMethod2(mockInput);

        // Assert
        if (result.StartsWith("Sorry, that was the wrong number"))
        {
            Console.WriteLine("Test Passed");
            return 0;
        }
    }
    return 1;
}

int RunTest3()
{
    // Arrange
    Func<string> mockInput = () => "";

    // Act
    string result = RunMethod2(mockInput);

    // Assert
    if (result == "Invalid guess")
    {
        Console.WriteLine("Test Passed");
        return 0;
    }
    return 1;
}

Console.WriteLine(RunTest1());
Console.WriteLine(RunTest2());
Console.WriteLine(RunTest3());

There’s a lot of code here, but all we’ve actually done is wrap the tests up in functions, and then returned a value based on the result of the test. This means that we can write something like this:

if (RunTest1() != 0 | RunTest2() != 0 | RunTest3() != 0)
{
    Console.WriteLine("Some tests failed");
}

In case you didn’t know, the single pipe (|) in C# in a bitwise or – that is, it will execute all conditions regardless of the result and then evaluate the result, a logical or (||) would only run the tests until one failed and then exit the condition.

This approach also helps with the second issue.

2. We were outputting to the console needlessly

We’re outputting to the console for two reasons: the first is to validate the tests; we can now simply remove all of those from the test, since we have an actual value that we can test against. The second reason is that the code itself outputs to the console. As has been mentioned in a previous post, there are ways to redirect the output of the console without mocking it; however, I’m trying to keep this series generic, and that is specific to the .Net console (although I strongly suspect that most languages provide a similar concept).

To get around this, we could replicate what we did in the second post; however, we can also take a slightly different approach and wrap the entire input / output functionality in its own class; for example:

    internal class ConsoleInputOutputWrapper
    {
        public void Output(string text) => Console.WriteLine(text);
        public string GetInput(string prompt)
        {
            Output(prompt);
            return Console.ReadLine();
        }
    }

This idea gives us some additional benefits – as you can see, we already have the prompt and input in a single method; and we could go further – we could do some validation inside the method, too; what if the user doesn’t enter anything:

        public string GetInput(string prompt)
        {            
            while (true)
            {
                Output(prompt);
                string? answer = Console.ReadLine();
                if (!string.IsNullOrWhiteSpace(answer)) return answer;
            }
        }

We can now replace the direct references to Console with references to this:

string RunMethod(Func<string> readData)
{
    var io = new ConsoleInputOutputWrapper();
    int myNumber = Random.Shared.Next(100) + 1;

    io.Output("Guess the number that I'm thinking between 1 - 100");
    string? guess = readData();
    string result = BusinessLogic2(myNumber, guess);
    io.Output(result);
    return result;
}

We haven’t actually changed anything here, though – the console is still being written to. We need to be able to replace the functionality within the system for our test. We can do that by replacing the concrete class with an interface.

Adding an Interface

Adding an interface is much simpler than it may sound. Let’s see what needs to change in our ConsoleInputOutputWrapper class:

internal class ConsoleInputOutputWrapper : IInputOutputWrapper

We’ve implemented an interface that we’ve named IInputOutputWrapper – we’ve named it this because it’s more generic (that is, it doesn’t actually need to be a Console).

The interface just needs to specify the public methods in the class:

    internal interface IInputOutputWrapper
    {
        void Output(string text);
        string GetInput(string prompt);
    }

Whilst this syntax is specific to C#, the concept of an interface is not.

While we’re introducing an interface, and to clean our code a little, we can extract both our RunMethod and BusinessLogic methods into their own class – let’s call it Game:

    internal class Game
    {
        public string RunMethod(Func<string> readData)
        {
            var io = new ConsoleInputOutputWrapper();
            int myNumber = Random.Shared.Next(100) + 1;

            io.Output("Guess the number that I'm thinking between 1 - 100");
            string? guess = readData();
            string result = BusinessLogic(myNumber, guess);
            io.Output(result);
            return result;
        }

        public string BusinessLogic(int myNumber, string guessedNumber)
        {
            if (string.IsNullOrEmpty(guessedNumber))
            {
                return "Invalid guess";
            }

            if (int.Parse(guessedNumber) == myNumber)
            {
                return "Well done, you guessed!";
            }
            else
            {
                return $"Sorry, that was the wrong number, I was thinking of {myNumber}";
            }
        }

    }

This makes things much simpler. We can now create a constructor, and pass in our new interface:

    internal class Game
    {
        private readonly IInputOutputWrapper _inputOutputWrapper;

        public Game(IInputOutputWrapper inputOutputWrapper)
        {
            _inputOutputWrapper = inputOutputWrapper;
        }

Now that we have this instance, we can simply replace the method with a reference to this instead:

        public string RunMethod()
        {            
            int myNumber = Random.Shared.Next(100) + 1;
            
            string guess = _inputOutputWrapper.GetInput("Guess the number that I'm thinking between 1 - 100");
            string result = BusinessLogic(myNumber, guess);
            _inputOutputWrapper.Output(result);
            return result;
        }

We can now update our tests to call this new class, but we can pass in our own version of the IInputOutputWrapper, which may look like this:

    internal class MockInputOutputWrapper : IInputOutputWrapper
    {
        public string GetInput(string prompt)
        {
            return "5";
        }

        public void Output(string text) { }
    }

The test would then look something like this:

    for (int i = 1; i <= 100; i++)
    {
        // Arrange
        var inputOutputWrapper = new MockInputOutputWrapper();
        var sut = new Game(inputOutputWrapper);

        // Act
        string result = sut.RunMethod();

        // Assert
        if (result == "Well done, you guessed!")
        {            
            return 0;
        }
    }
    return 1;

Next, we’ll skip number 3 and jump to 4.

4. The tests were not deterministic – they were dependent on the result of a pseudo random number

We can use the same pattern to create a wrapper for our random number chooser:

    internal class RandomNumberChooser : IRandomNumberChooser
    {
        public int Choose() =>
            Random.Shared.Next(100) + 1;        
    }

We can then mock that out, as before:

internal class MockRandomNumberChooser : IRandomNumberChooser
{
    public int Choose() => 12;
}

This definitely works, but it’s not brilliant. We have a few remaining issues – for example, if we want to test the number are the same, or different, we’ll need two mock classes. There are ways around this, too – for example:

    internal class MockInputOutputWrapper : IInputOutputWrapper
    {
        private readonly string _inputValue;

        public MockInputOutputWrapper(string inputValue) =>
            _inputValue = inputValue;        

        public string GetInput(string prompt) => _inputValue;        

        public void Output(string text) { }
    }

We’ll come back to neater ways to achieve this in a future post, but for now, let’s put all this together and introduce a test framework.

Introducing a Test Framework

Test frameworks give you four basic things (some, in fact most, do more, but these are the absolute basics that you need – otherwise, you might as well roll your own):

1. A return value from the test run to determine whether the tests pass or fail
2. An ability to assert a value is in a given state
3. Some kind of integration into your IDE
4. Method discovery (that is, some way to mark your tests as tests)

For this example, we’ll use xUnit.net. Every language has its own options here – in .Net I’ve used MS Test, Nunit, and xUnit – and they’re all broadly the same; I’ve also seen libraries in Javascript and Python and, again, they mostly do the same stuff.

We’ll need to install the following libraries:

Install-Package Microsoft.Test.Sdk
install-package Xunit
Install-Package Xunit.Runner.Console
Install-Package Xunit.Runner.VisualStudio

This will enable you to create a test such as this:

[Fact]
public void RunMethod_GuessedCorrectly_CorrectTextReturned()
{
    // Arrange
    var inputOutputWrapper = new MockInputOutputWrapper("12");
    var randomNumberChooser = new MockRandomNumberChooser();
    var sut = new Game(inputOutputWrapper, randomNumberChooser);

    // Act
    string result = sut.RunMethod();

    // Assert
    Assert.Equal("Well done, you guessed!", result);
}

We no longer need to run this 100 times, because we can force a correct and incorrect guess:

        [Fact]
        public void RunMethod_GuessedIncorrectly_CorrectTestReturned()
        {
            // Arrange
            var inputOutputWrapper = new MockInputOutputWrapper("13");
            var randomNumberChooser = new MockRandomNumberChooser();
            var sut = new Game(inputOutputWrapper, randomNumberChooser);

            // Act
            string result = sut.RunMethod();

            // Assert
            Assert.StartsWith("Sorry, that was the wrong number", result);
        }

Summary

We’ve now seen how we can manually mock functionality, and how that can help us to accurately test methods; we’ve also introduced a testing framework. In the next post, we’ll discuss mocking frameworks, and how they can make this even easier. We’ll also re-visit the test resilience.

Introduction to Unit Tests (with examples in .Net) – Part 2 – Refactoring and Mocking

This forms the second in a short series of posts on unit tests. You can find the first post in this series here.

In this post, I’ll be expanding the points raised in the first post to cover a slightly more realistic scenario, and offering some tips of how re-factoring might help with the creation of unit tests. We’ll also cover the basic principles behind mocking – I’m intending to cover this in more detail in a future post of this series.

A Quick Recap

You’re welcome (and encouraged) to go back to the first post in the series; however, to summarise, we discussed the Arrange/Act/Assert pattern, and how it can help us structure a unit test; we spoke about the FIRST principles of testing, and thereby the attributes that we should look for in a good unit test.

What we specifically didn’t cover was any testing frameworks, the concept of mocking or any mocking frameworks, or how to write a unit test in a scenario where you’re not simply adding two numbers together.

A More Realistic Unit Test

If we take an example of any level of complexity, we might question some of the points that were made in the first post. After all, very few methods would simply take two numbers and add them together – or, if they do, perhaps we need to reconsider the language that we’re using.

Let’s look at a simple console application:

int myNumber = Random.Shared.Next(100) + 1;

Console.WriteLine("Guess the number that I'm thinking between 1 - 100");
var guess = Console.ReadLine();
if (string.IsNullOrEmpty(guess))
{
    Console.WriteLine("Invalid guess");
    return;
}

if (int.Parse(guess) == myNumber)
{
    Console.WriteLine("Well done, you guessed!");
}
else
{
    Console.WriteLine($"Sorry, that was the wrong number, I was thinking of {myNumber}");
}

If you had to test this code, how would you do it?

In fact, it’s really difficult, because every time you run it, the number is different. This is a simple piece of code, there’s only 3 code paths; arguably, your strategy could be: run it once and enter a blank value, run it once and enter a non-numeric value, run it 100 more times and hope that you’ll get the number right once.

Writing a Test

As before, let’s start with the manual test that we’ve just described; arguably, we could simply automate this. We’d probably do something like this:

        public static void RunTest()
        {
            // Run method here - check that a blank entry works

            // Run method here - check that a numeric entry works

            for (int i = 0 ; i < 100; i++)
            {
                // Run method here - exit this loop once we've determined that we have a correct and incorrect guess

            }
        }

In fact, running that exact test would be possible – we could simply redirect the console input and output; however, for the purposes of this post, we’ll bypass that method (as it is quite specific to writing a .Net Console app), and we’ll re-factor our code a little.

Refactoring

We can refactor it by splitting the method into two; one method that accepts the input, and one that runs the business logic:

void RunMethod()
{
    int myNumber = Random.Shared.Next(100) + 1;

    Console.WriteLine("Guess the number that I'm thinking between 1 - 100");
    var guess = Console.ReadLine();
    BusinessLogic(myNumber, guess);
}

void BusinessLogic(int myNumber, string guessedNumber)
{
    if (string.IsNullOrEmpty(guessedNumber))
    {
        Console.WriteLine("Invalid guess");
        return;
    }

    if (int.Parse(guessedNumber) == myNumber)
    {
        Console.WriteLine("Well done, you guessed!");
    }
    else
    {
        Console.WriteLine($"Sorry, that was the wrong number, I was thinking of {myNumber}");
    }
}

All we’ve done here is split the method into two methods – the code is exactly the same as it was before. However, now we can run the code in our test without worrying about the input:

        public static void RunTest()
        {
            // Check that a blank entry works
            BusinessLogic(3, "");

            // Check that a non-numeric entry works
            BusinessLogic(3, "aardvark");

            for (int i = 1; i <= 100; i++)
            {
                // Check that false and true numbers work
                BusinessLogic(i, "2");
            }
        }

It still feels a lot like we’re only testing half of the code. We aren’t testing the calling method.

Mocking

Let’s refactor a little further. Instead of using the console, we’ll simply create our own method that performs the same task:

private static string? GetInput() => Console.ReadLine();    

Again, no real change here, we’re just wrapping the code that accepts input in a method that we control.

Now that we’ve done this, we can use our own method to accept input, instead of the Console methods. There’s a number of ways we could do this but, perhaps the easiest, is to pass the GetInput method into the RunMethod method as a parameter:

public static void RunMethod(Func<string> readData)
    {

        int myNumber = Random.Shared.Next(100) + 1;

        Console.WriteLine("Guess the number that I'm thinking between 1 - 100");
        string? guess = readData();
. . .

Here, we’re simply changing two things: we’re accepting a delegate into our main method, and then we’re calling that, instead of the Console.ReadLine().

What’s the point of doing that? Well, now that we control that function as a parameter, we can mock the function, and replace it with our own functionality.

In fact, we are not technically discussing a mock here, but a stub. For the purpose of this post, we’ll simply group them together with the working definition that a mock is: “anything that replaces functionality for the purpose of testing”. I intend to re-visit this in a future post and go into more detail on the difference between the two.

Let’s jump to our test.

Arrange

In the test, we can now replace this functionality with a specific value:

        public static void RunTest()
        {
             // Arrange
            Func<string> mockInput = () => "5"; . . .

We’ve now established the input of the method, the next step is to be able to assert that the test worked. In fact, that’s very difficult with the code as it currently is, because we just display output to the user. To finish this post off, we’ll refactor this as little as we can; imagine we take the business logic function and change it to be like this:

string BusinessLogic(int myNumber, string guessedNumber)
{
    if (string.IsNullOrEmpty(guessedNumber))
    {        
        return "Invalid guess";
    }

    if (int.Parse(guessedNumber) == myNumber)
    {
        return "Well done, you guessed!";
    }
    else
    {
        return $"Sorry, that was the wrong number, I was thinking of {myNumber}";
    }
}

All we’ve changed here is that we’re returning the string, instead of outputting it. We can then change the calling method to do the output:

string RunMethod(Func<string> readData)
{
    int myNumber = Random.Shared.Next(100) + 1;

    Console.WriteLine("Guess the number that I'm thinking between 1 - 100");
    string? guess = readData();
    string result = BusinessLogic(myNumber, guess);
    Console.WriteLine(result);
    return result;
}

Same idea again, a very small change of writing the output, and returning the result again. The functionality hasn’t changed, but now we have something to test against.

Assert

We can now write out test method to look something like this:

for (int i = 1; i <= 100; i++)
{
    // Arrange
    Func<string> mockInput = () => "5";

    // Act
    string result = RunMethod(mockInput);

    // Assert
    if (result == "Well done, you guessed!")
    {
        Console.WriteLine("Test Passed");
        break;
    }
}

for (int i = 1; i <= 100; i++)
{
    // Arrange
    Func<string> mockInput = () => "5";

    // Act
    string result = RunMethod(mockInput);

    // Assert
    if (result.StartsWith("Sorry, that was the wrong number"))
    {
        Console.WriteLine("Test Passed");
        break;
    }
}

{
    // Arrange
    Func<string> mockInput = () => "";

    // Act
    string result = RunMethod(mockInput);

    // Assert
    if (result == "Invalid guess")
    {
        Console.WriteLine("Test Passed");
    }
}

There’s three distinct tests here and, unless unlucky, they’ll all pass. There’s definitely some work left to do here, as we still have the following problems:

1. Although the tests can pass, we have to visually ascertain that.
2. We’re outputting to the console needlessly.
3. Our tests are not resilient – if I change a single character in the user output, the tests will break.
4. The tests are not deterministic – they are dependent on the result of a pseudo random number.

In the next post, we’ll address these issues: we’ll introduce a test framework, and further refactor this code such that we can be confident that cosmetic changes will not break the tests.