带xUnit的Moq和AutoMoq(AutoFixture)依赖注入

时间:2019-04-12 18:57:23

标签: unit-testing .net-core xunit autofixture automoq

我正在写这篇文章是因为我已经尝试了一下,以解决自己的问题。无论出于何种原因,我都能找到的每个示例似乎都表明这是开箱即用的,但是每当我尝试执行相同操作时,总是会出错。基本上,我有一个具有两个属性的控制器,它们是通过注入的。 DI,比方说

public class SomeController
{
    private ISomeInterface _i;
    private MyConfig _c;

    public SomeController(ISomeInterface i, MyConfigContext cxt) // Where cxt is Type of DbContext
    {
        _i = i;
        _c = cxt.Configs.FirstOrDefault();
    }

    public OkResult PostModel(SomeModel c)
    {
        // Do things
        return Ok();
    }
}

在使用xUnit,Moq和AutoFixture的测试中,我试图避免手动实例化依赖项BC

public class SomeControllerTests
{
    private MyDbContext _cxt;
    private Fixture _fixture;

    public SomeControllerTests()
    {
        _cxt = GetCxt() // GetCxt() just returns a context instance, nothing special
       _fixture = new Fixture();
       _fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
       _fixture.Customizations.Add(
          new TypeRelay(
              typeof(ISomeInterface),
              typeof(SomeConcreteClass)
          )
       );
    }

    [Fact, AutoData]
    public void PostStatus_ReturnsOk_GivenValidRequest()
    {
        SomeController c = _fixture.Create<SomeController>();
        SomeModel m = _fixture.Create<SomeModel>();
        var result = c.PostModel(m);

        Asset.IsType<OkResult>(result);
    }
}  

使用上面的方法,我在运行测试时得到NotImplementedException,并且它不会告诉我确切的未实现的内容,因此我无法知道问题所在。我必须在文档中缺少某些内容。我想使用AutoFixture使测试更持久,但到目前为止,尝试使用它一直很痛苦。我真的不想只为了运行测试而手动模拟/存根整个应用程序。理想情况下,我想使用AutoFixture文档中显示的语法,其中将与测试相关的实例放在测试的参数中,它们是为您创建的,但是我没有运气,例如...

[Theory, AutoData]
SomeTestMethod(SomeController c, SomeModel m)
{
    var result = c.PostModel(m);

    Assert.IsType<OkResult>(result);
}

感谢您的阅读(:

2 个答案:

答案 0 :(得分:0)

我认为这里发生了两件事。

首先,我假设您的控制器继承自ControllerBase。 Autofixture似乎无法创建ControllerContext,您可以通过在安装过程中注入一个实例来解决此问题。

[Theory, AutoData]
SomeTestMethod(SomeController c, SomeModel m)

第二部分与此结构的测试有关

public class ControllerAutoDataAttribute : AutoDataAttribute
{
    public ControllerAutoDataAttribute() : base(() =>
    {
        var fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
        fixture.Customizations.Add(
           new TypeRelay(
               typeof(ISomeInterface),
               typeof(SomeConcreteClass)
           )
        );
        fixture.Inject(new ControllerContext());
        return fixture;
    }){ }
}

将在调用SomeControllerTests()构造函数之前构造注入的类型(SomeController和SomeModel)。这意味着夹具定制为时已晚。解决方法是创建一个自定义AutoDataAttribute,然后将自定义移到那里,就像这样:

[Theory, ControllerAutoData]
SomeTestMethod(SomeController c, SomeModel m)
{
    var result = c.PostModel(m);

    Assert.IsType<OkResult>(result);
}

然后更改您的测试方法以像这样使用它:

{{1}}

答案 1 :(得分:0)

尝试添加下一个属性并使用它代替AutoData

using AutoFixture.AutoMoq;
using AutoFixture.Xunit2;

namespace Cats
{
    public class AutoMoqDataAttribute : AutoDataAttribute
    {
        public AutoMoqDataAttribute()
            : base(() => new Fixture().Customize(new AutoMoqCustomization()))
        {
        }
    }
}

[Theory, AutoMoqData]
SomeTestMethod(SomeController c, SomeModel m)
{
    var result = c.PostModel(m);

    Assert.IsType<OkResult>(result);
}