如何在.net中模拟函数委托

mklgxw1f  于 2022-12-20  发布在  .NET
关注(0)|答案(1)|浏览(130)

我在控制器中有一个Func<>属性,我想知道如何模拟它。
下面是我的代码:

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

下面是控制器构造函数中的用法:

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

下面是在单个方法和API调用中的用法:

var id = GetId (Request);

上面的Func<>属性在控制器及其构造函数中的所有API调用中使用。我尝试模拟它,这样我在编写单元测试时就不必处理它了。有什么建议吗?

hxzsmxv2

hxzsmxv21#

归功于@Nkosi在评论中对问题的原始解决方案。

    • 说明**

因为委托是在控制器的构造函数中初始化的,所以必须先构造控制器,然后在构造之后分配委托,这是可以做到的,因为GetId有一个公共setter。
所以你的测试看起来像

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

    // act
    var someResult = controller.SomeMethod(...);
    ...
}
    • 处理可能的重构**

将setter设置为private以防止开发人员在生产代码中重新访问委托是可能的,也可能是一个好主意。

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

然而,如果这样做,上面的测试将无法编译。要解决这个问题,可以通过反射在测试中访问setter,但这会使测试变得脆弱。
要解决这个问题,一个更好的解决方案是在构造函数中添加一个依赖项,并删除Func<>属性,我们将该依赖项命名为IIdProvider

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);
        ...
    }
}

现在,您可以修改您的测试来创建控制器,该控制器从您创建的模拟框架或存根中传递一个真正的模拟。

[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(...);
        ...
    }
}

相关问题