Search code examples
c#unit-testingstub

Is it possible to shim a method on a stub?


Let's say I have (for instance) a stubbed logger, but want to unit test the messages being creates when used by something.

For Instance:
I would like to be able to get-at the last Log message given a scenario, like so...

public class FooService
{
    public FooService(ILogger logger)
    {
        Logger = logger;
        StatusManager = new StatusManager();
    }
        
    public ILogger Logger  { get; }
    
    public StatusManager StatusManager  { get; }
    
    public void Execute()
    {
        var status = StatusManager.GetStatus();
        
        if(status.CannotProceed)
        {
            Logger.Log("Cannot proceed");
            return;
        }
    }
}

public class ILogger LoggerStub()
{
    public void Log(string value)
    {
        // I would like to be able to stub this method & access the "value"
    }
}

[TestClass]
public class FooServiceUnitTests
{
    [TestMethod]
    public void FooService_shuts_down_correctly()
    {
        var expecedMessage = "Cannot proceed";
        var somelocalFn = [some kind of stub I can use to get the lass meggase logged]???
    
        // -----
        // ARRANGE
        var logger = new LoggerStub();
        var service = new FooService(logger);
        
        service.StatusManager.CannotProceed = true;
    
        // Stub the method somehow?
        Logger.Log = () => somelocalFn
    
        // -----
        // ACT
        service.Execute();
        
        // -----
        // ASSERT
        var message = somelocalFn???
        
        Assert.AreEqual(message, somelocalFn);
    }
}

Solution

  • You could use the following approach (original formatting preserved):

    public class ILogger LoggerStub()
    {
        public string LastMessage {get; private set;}
        public void Log(string value)
        {
            // I would like to be able to stub this method & access the "value"
            LastMessage = value;
        }
    }
    

    and then in the unit test:

    [TestMethod]
    public void FooService_shuts_down_correctly()
    {
        var expecedMessage = "Cannot proceed";
    
        // -----
        // ARRANGE
        var logger = new LoggerStub();
        var service = new FooService(logger);
        
        service.StatusManager.CannotProceed = true;
     
        // -----
        // ACT
        service.Execute();
        
        // -----
        // ASSERT
        var message = logger.LastMessage;
        
        Assert.AreEqual(expectedMessage, message, "Incorrect message logged!");
    }