Home > OS >  How to mock func delegate in .net
How to mock func delegate in .net

Time:12-20

I have a Func<> property in a controller, and I am wondering how can I mock it.

Here is my code:

public Func<HttpRequest, string> GetId { get; set; }

Here is the usage in the controller's constructor:

GetId = req => req.HttpContext.Items["random-id"].ToString();

and here is the usage in individual methods and API calls:

var id = GetId (Request);

The above Func<> property is used in all the API calls in the controller and its constructor. I am trying to mock it so I don't have to deal with that while writing unit tests. Any suggestions?

CodePudding user response:

Credit to @Nkosi in the comments to the question for the original solution.

Explanation

Because your delegate is initialized in the constructor of the controller, you will have to first construct the controller then assign a delegate after construction, which you can do because GetId has a public setter.

So your test would look something like

[Test]
public void SomethingTest()
{
    // arrange
    var controller = new YourController(...);
    controller.GetId = req => "SomeFakeId";

    // act
    var someResult = controller.SomeMethod(...);
    ...
}

Possible refactorings

It is possible and probably a good idea to make the setter private to prevent developers from changing the delegate in production code to something that might not be suitable. In that case you can make the setter private (in fact you can make the whole property private if the delegate is not meant to be accessed at all outside of the controller).

public Func<HttpRequest, string> GetId { get; private set; }

or

private Func<HttpRequest, string> GetId { get; set; }

However, if you did that, the above test would not compile. To fix that, you could access the setter through reflection but that would make the test brittle.

A better solution would be to add a dependency in the constructor, and remove the Func<> property. Let us call that dependency IIdProvider. The production code would then look something like

public interface IIdProvider
{
    string GetId(HttpRequest request);
}

public class ContextItemsIdProvider : IIdProvider
{
    public string GetId(HttpRequest request)
        => request.HttpContext.Items["random-id"].ToString()
}

public class YourController: ...
{
    public IdProvider { get; private set; }

    public YourController(..., IIdProvider idProvider)
    {
        IdProvider = idProvider;
    }

    public IActionResult SomeMethod()
    {
        var id = IdProvider(Request);
        ...
    }
}

Now, you can modify your test to create the controller, passing in a true mock from a mocking framework or a stub that you create. Here is an example using a stub:

[TestFixture]
public class YourControllerTests
{
    private class IdProviderStub : IIdProvider
    {
        public string GetId(HttpRequest request)
            => "SomeFakeId";
    }

    [Test]
    public void SomethingTest()
    {
        // arrange
        var controller = new YourController(..., new IdProviderStub());
 
        // act
        var someResult = controller.SomeMethod(...);
        ...
    }
}

CodePudding user response:

I was able to assign a mock func to the property of controller in setup function. Something like this:

        [SetUp]
        public void Setup()
        {
            var funcMock = new Mock<Func<HttpRequest, string>>();
            _testController= new TestController();
            _testController.GetId  = funcMock.Object;
        }

  • Related