Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Stubbing out" a function for unit tests

I have various methods that I would like to unit test using Visual Studio's built in unit testing capability for C#. Things have been going pretty smoothly, but I've run into a scenario where I want to "stub out" a dependency on a particular function call.

Namely, I have some methods that are in the following format:

public class ClassWithMethodsIWantToUnitTest 
{
    public void myFcn(object someArg)
    {
        ...
        LoggerService.Instance.LogMessage("myMessage");
        ...
    }
}

So basically, I want my unit test to simply verify that the call to "LogMessage" has occurred. I don't want to actually check a log file or anything. I want a way to see if the LoggerService line has been hit and executed.

LoggerService is a singleton, and if possible, I don't want to modify the code just for unit testing.

Based on the format of this problem, it seems to me that it should be possible to somehow take control of the code in my unit test. In other words, is there a way for me to make a fake version of LogMessage such that I can use it for my unit test? I don't want the "real" LogMessage function to be called if possible. I just want to test that the code hit the path that called the function.

Does this make any sense? Is this possible?

like image 410
Kirby Avatar asked Dec 20 '25 11:12

Kirby


2 Answers

It certainly makes sense and is not an unknown problem.

Unfortunately you will probably need to change the code, so that it accepts dependency injection. That is, when testing you should be able to inject a specially crafted test object (a mock) instead of the real thing. In your case it probably means being able to set LoggerService.Instance to a special mock object.

The second thing you need is the fake logger instance that you will test against. You probably want a mock, which is a special object that can be set up to check behaviour of the caller. There are several mock frameworks around and I really recommend that you use one instead of trying to roll your own.

like image 149
Anders Abel Avatar answered Dec 23 '25 00:12

Anders Abel


Anders' answer was definitely the "canonical" way of approaching the problem, but in .NET 4.5, there's a second option:

The Fakes framework.

It lets you add a "fakes" assembly to your unit test project that accepts a delegate to perform in place of the actual implementation of a method. Here's an example using File.ReadAllText

    [TestMethod]
    public void Foo()
    {
        using (ShimsContext.Create())
        {
            ShimFile.ReadAllTextString = path => "test 123";
            var reverser = new TextReverser();
            const string expected = "321 tset";
            //Act
            var actual = reverser.ReverseSomeTextFromAFile(@"C:\fakefile.txt");
            //Assert
            Assert.AreEqual(expected, actual);
        }
    }

What that test method is doing is temporarily (within the scope of the ShimsContext) replacing the implementation of File.ReadAllText with the lambda I provided. In this case, any time ReadAllText is called, it returns the string "test 123".

It's slower than regular DI, but if you're absolutely tied to a specific implementation of a singleton, it could be exactly what you need. Read more about it here.

like image 20
Daniel Mann Avatar answered Dec 23 '25 01:12

Daniel Mann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!