c# - 在通用测试助手中管理由 AutoFixture 馈送到 MVC Controller 的服务

标签 c# tdd moq autofixture

我是 AutoFixture 的新手,正在尝试为团队中不太喜欢 TDD 的开发人员在我的测试环境上创建一个友好的扩展。这是代码:

public class HomeController : Controller
{
    private readonly ISomeService _someService;

    public HomeController(ISomeService someService)
    {
        _someService = someService;
    }

    public ActionResult Index()
    {
        _someService.SomeMethod();
        return View("Index");
    }
}

public class ControllerContext<T> where T : Controller
{
    protected static T ControllerUnderTest;
    private static IFixture _fixture;

    public ControllerContext()
    {
        _fixture = new Fixture().Customize(new AutoMoqCustomization());
        _fixture.Customize<ControllerContext>(c => c.Without(x => x.DisplayMode));
        ControllerUnderTest = _fixture.Create<T>();
    }

    protected static Mock<TDouble> For<TDouble>() where TDouble : class
    {
        //var mock = _fixture.Create<TDouble>();
        var mock = _fixture.Create<Mock<TDouble>>();
        return mock;
    }
}

所以扩展是 For 方法 - 当我检查具有注入(inject)的“ISomeService”的 ControllerUnderTest 时,它有一个很好的实例注入(inject),并且它肯定会调用该方法我断言反对。当我检查“For”方法中创建的模拟时,它似乎与注入(inject) Controller 的版本相同,但它不会Verify!

public class EXAMPLE_When_going_to_home_page : ControllerContext<HomeController>
{
    Because of = () =>
    {
        ControllerUnderTest.Index();

    };

    It should_do_something = () =>
    {
        //This throws a 'Invocation was not performed'
        For<ISomeService>().Verify(x => x.SomeMethod());
    };

    Establish context = () =>
    {

    };
}

我正在努力寻找有人做类似事情的例子,我知道我肯定在这里做了一些愚蠢的事情,但在我看来,这个测试应该通过?

最佳答案

Create每次都会创建一个新的匿名实例,除非您卡住(通过 .Freeze<T>() 或 AutoFixture.Xunit 的 [Frozen] )实例。这意味着注入(inject) HomeController 的值与 For 返回的不同.

有几种可能的解决方案,所有这些最终都将涉及卡住该值或注入(inject)要使用的值。

一个示例如下所示:

public class ControllerContext<T> where T : Controller
{
    private static Lazy<T> _controllerFactory;
    private static IFixture _fixture;

    public ControllerContext()
    {
        _fixture = new Fixture().Customize(new AutoMoqCustomization());
        _fixture.Customize<ControllerContext>(c => c.Without(x => x.DisplayMode));
        _controllerFactory = new Lazy<T>(() => _fixture.Create<T>());
    }

    protected static Mock<TDouble> For<TDouble>() where TDouble : class
    {
        var mock = _fixture.Freeze<Mock<TDouble>>();
        return mock;
    }

    protected static T ControllerUnderTest
    {
        get { return _controllerFactory.Value; }
    }
}

public class EXAMPLE_When_going_to_home_page : ControllerContext<HomeController>
{
    static Mock<ISomeService> SomeService;

    Because of = () =>
    {
        SomeService = For<ISomeService>();
        ControllerUnderTest.Index();
    };

    It should_do_something = () =>
    {
        //This throws a 'Invocation was not performed'
        SomeService.Verify(x => x.SomeMethod());
    };

    Establish context = () =>
    {

    };
}

这个更改版本的重点是首先 Freeze仅在创建 Controller 的匿名实例之后才在服务模拟上调用。因为For的方式现在使用方法,您可能应该将其重命名为 GetService .

关于c# - 在通用测试助手中管理由 AutoFixture 馈送到 MVC Controller 的服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18955717/

相关文章:

c# - 如何使用 Moq 测试方法调用顺序

c# - 使用ServiceStack上传图片文件

python - QMessageBox 的功能测试...为什么不起作用?

c# - 如何使用 Moq 在 .NET Core 2.1 中模拟新的 HttpClientFactory

unit-testing - 需求不明确的 TDD

Django assertEqual 不显示实际值与预期值

c# - 使用最小起订量更改参数

c# - 调整并发字典大小时遇到​​ Synchronization LockException

c# - 如何让 Windows 窗体应用程序与类(class)一起工作?

C# TcpClient 超时