Home > front end >  How to write a XUnit test case for a method that does return void
How to write a XUnit test case for a method that does return void

Time:01-28

How to write a XUnit test case for a method that does return void ?

The method:

    public static void Print(string x)
    {
        Console.WriteLine(x);
    }

XUnit Test Case - (Which is not completed)

    [Fact]
    public void ActionDelegatePrintTest()
    {
        Action<string> a= MaClass.Print;
         
        // How do I complete this test case ?

    }

I cannot simply use Assert.Equal() as it doesn't return anything. So how am I suppose to write the Assert statement ?

CodePudding user response:

You can only test for side effects, and the function you are testing doesn't allow you to mock anything, so you can't test for anything.

If you really want to test that something was written to the console, then you need to abstract that ability and then test that.

interface IConsoleWriter
{
   void WriteLine(string text);
}

IConsoleWriter _consoleWriter;
public void Print(string x)
    {
        _consoleWriter.WriteLine(x);
    }

[Fact]
public void ActionDelegatePrintTest()
{
    var sut = Mock.Of<IConsoleWriter>();
    sut.Print("Hello");
    sut.Verify(x=>x.Print("Hello"), Times.Once);  //<-- or whatever you need to test
}

CodePudding user response:

You can test that the method you want was called, and you can test that any other methods inside that void function are called, they take different approaches tough.

Assuming you are using or are willing to use Moq you can follow my example

using Moq;
using Xunit;

namespace Tests;

public interface IMyLogger
{
    void Log();

    void Error();

    void Fatal();
}

public interface IMyClass
{
    void DoStuff();

    void DoSomethingElse();

    void CalledFromSomewhereInMyClass();
}

public class MyClass : IMyClass
{
    private readonly IMyLogger _logger;
    public MyClass(IMyLogger logger)
    {
        this._logger = logger;
    }

    public void DoStuff()
    {
        this._logger.Log();
    }

    public void DoSomethingElse()
    {
        this._logger.Error();
        this.CalledFromSomewhereInMyClass();
    }

    public void CalledFromSomewhereInMyClass()
    {
        this._logger.Error();
        this._logger.Fatal();
    }
}

public class MyClassTests
{
    private readonly Mock<IMyLogger> _loggerMock;
    public MyClassTests()
    {
        this._loggerMock = new Mock<IMyLogger>();
    }

    // Testing just that the method is called
    [Fact]
    public void TestDoStuffIsCalled()
    {
        var myClassMock = new Mock<IMyClass>();
        var myClassInstantiation = myClassMock.Object;

        myClassInstantiation.DoStuff();
        myClassMock.Verify(f => f.DoStuff(), Times.Once);
    }

    // Let's ensure the Logger.Log method is called
    [Fact]
    public void TestLoggerInsideDoStuffIsCalled()
    {
        var myClass = new MyClass(this._loggerMock.Object);
        myClass.DoStuff();

        this._loggerMock.Verify(f => f.Log(), Times.Once);
    }

    // Let's test chained calls to IMyLogger
    [Fact]
    public void TestChainCalls()
    {
        var myClass = new MyClass(this._loggerMock.Object);

        myClass.DoSomethingElse();
        this._loggerMock.Verify(f => f.Log(), Times.Never);

        // Note that Error is called from DoSomethingElse() and CalledFromSomewhereInMyClass() so it should be called twice
        this._loggerMock.Verify(f => f.Error(), Times.Exactly(2));
        this._loggerMock.Verify(f => f.Fatal(), Times.Once);
    }
}

CodePudding user response:

If you want to test whether an exact parameter was passed properly to some dependency that you can mock see the other answers.

But if you just want to assert that that the method was executed properly without throwing an exception, and you couldn't find something like NUnit's Assert.DoesNotThrow in xUnit, then this is how you can work it around:

var exception = Record.Exception(() => MaClass.Print("some valid input"));
Assert.Null(exception);

And actually you can assert invalid parameters that throw some exception in a very similar way.

  •  Tags:  
  • Related