Joseph Katzman
Joseph Katzman

Reputation: 2083

Is a call of the static method is a test case for unit testing?

This is a simplified model of my class.

public static FooFactory
{
    public void CreateFooByUrl(string url) 
    {
        try 
        {
           // business logic
        }
        catch(Exception exc) 
        {
           ApplicationLogger.LogError(exc);
        }
    }
}

ApplicationLogger is a static class which is used across the solution. How can I verify that error was logged?

This is example of my test method.

[TestMethod]
public void CreateFooExpectedError()
{
    // Arrange
    string testUrl = "fakeUrl";

    // Act
    FooFactory.CreateFoo(testUrl);

    // Assert
    /ApplicationLogger.LogError();
}

How to check that LogError method was called? Does it a test case?

Upvotes: 0

Views: 132

Answers (1)

mason
mason

Reputation: 32704

You have a hard dependency on ApplicationLogger. That's not good. Now you can't test that CreateFooByUrl works without actually logging something. Instead, have it use an IApplicationLogger (an interface) and then you can provide a mock implementation of that interface as part of unit testing. This will probably mean you either need to make FooFactory non static (you can't have a non static method in a static class anyways like you've shown) or change CreateFooByUrl to accept an IApplicationLogger as a parameter (messier).

Here's the clean way:

public interface IApplicationLogger
{
    void LogError(Exception exception);
}

public class ApplicationLogger : IApplicationLogger
{
    public void LogError(Exception exception)
    {
        //do stuff
    }
}

public class FooFactory
{
    private readonly IApplicationLogger _logger;

    public FooFactory(IApplicationLogger logger)
    {
        _logger = logger;
    }

    public void CreateFooByUrl(string url) 
    {
        try 
        {
           // business logic
        }
        catch(Exception exception) 
        {
           _logger.LogError(exception);
        }
    }
}

//now for the unit test
public void TestCreate()
{
    //arrange
    var mockLogger = new Mock<IApplicationLogger>(MockBehavior.Strict);
    mockLogger.Setup(m => m.LogError(It.IsAny<Exception>()));

    var factory = new FooFactory(mockLogger.Object);

    //act
    factory.CreateFooByUrl("something that will cause exception");


    //assert
    mockLogger.Verify(m => m.LogError(It.IsAny<Exception>()));
}

This is much better from a Separation of Concerns perspective. Why should FooFactory care how things get logged? It just needs to be able to log things. That's why it's better to code against an interface. Then if you ever want to switch logging implementations you just have to create a new class that implements IApplicationLogger and everything will magically work.

Upvotes: 4

Related Questions