AutoFixture作为一个自动模拟容器与自动模拟的区别是什么?

12

我开始使用moq,但据我所知,即使我真的不关心它们,我始终必须模拟所有可能被调用的方法。有时候构建模拟需要太长时间,以至于你忘记了自己想做什么。因此,我一直在寻找自动模拟工具,但我不确定该使用哪一个。

AutoFixture作为自动模拟容器

自动模拟

我完全不知道如何使用第一个工具。第二个工具我有点理解,但从未真正尝试过。

我不确定哪个工具更好。唯一知道的是我已经在使用AutoFixtures,这是第一个工具的依赖项。

因此,也许从长远来看,使用第一个工具是有意义的,但就像我所说,我找不到任何基本教程来使用它。

编辑

我正在尝试跟随“Nikos Baxevanis”的示例,但遇到了错误。

Failure: System.ArgumentException : A matching constructor for the given arguments was not found on the mocked type.
  ----> System.MissingMethodException : Constructor on type 'DatabaseProxyded46c36c8524889972231ef23659a72' not found.


var fixture = new Fixture().Customize(new AutoMoqCustomization());
        var fooMock = fixture.Freeze<Mock<IFoo>>();
       // fooMock.Setup(x => x.GetAccounts(It.IsAny<IUnitOfWork>()));
        var sut = fixture.CreateAnonymous<AdminService>();

        sut.Apply();
        fooMock.VerifyAll();

我认为是因为我的petapoco unitOfWork属性

PetaPoco.Database Db { get; }

我不确定是否需要进行模拟或其他处理。


关于您遇到的异常,您使用AutoFixture和Auto-Mocking的方式没有问题。如果您可以在问题中包含测试中使用的所有类型的源代码,我很乐意提供进一步的帮助。 - Nikos Baxevanis
我一直在浏览代码,问题出现在我的服务层方法(我正在尝试进行单元测试的方法)中。已经发生了调用。虽然我有一个作为接口的工作单元,但属性Db不是接口,这导致它崩溃。我必须模拟它,但petapoco没有接口。所以我想要包装它。 - chobo2
1个回答

26

虽然我从未使用过 moq-contrib Automocking,但我可以为使用 AutoFixture 作为自动模拟容器提供一些信息。

目前支持 Moq、Rhino Mocks、FakeItEasy 和 NSubstitute。只需安装适当的扩展 AutoMoqAutoRhinoMocksAutoFakeItEasyAutoNSubstitute

一旦您安装了其中一个自动模拟扩展,额外的调用是:

var fixture = new Fixture()
    .Customize(new AutoMoqCustomization());

(或者如果您正在使用Rhino Mocks)

var fixture = new Fixture()
     .Customize(new AutoRhinoMockCustomization());

(或者如果您正在使用FakeItEasy)

var fixture = new Fixture()
     .Customize(new AutoFakeItEasyCustomization());

(或者如果你正在使用NSubstitute)

var fixture = new Fixture()
     .Customize(new AutoNSubstituteCustomization());

例子1

public class MyController : IController
{
    public MyController(IFoo foo)
    {
    }
}

public interface IFoo
{
}

以下是如何使用AutoFixture创建MyController类实例的方法:
var fixture = new Fixture()
    .Customize(new AutoMoqCustomization());

var sut = fixture.CreateAnonymous<MyController>();

现在,如果您检查sut变量,您将看到IFoo是一个模拟实例(类型名称类似于Castle.Proxies.IFooProxy)

示例2

这个示例扩展了上一个示例。

您可以指示AutoFixture使用您自己预配置的模拟实例:

var fooMock = fixture.Freeze<Mock<IFoo>>();
// At this point you may setup expectation(s) on the fooMock.

var sut = fixture.CreateAnonymous<MyController>();
// This instance now uses the already created fooMock.
// Verify any expectation(s).

基本上就是这样 - 但它可以更进一步!

以下是使用AutoFixture 声明式和xUnit.net 扩展程序的先前示例。

示例1

[Theory, AutoMoqData]
public void TestMethod(MyController sut)
{
    // Start using the sut instance directly.
}

例子2

[Theory, AutoMoqData]
public void TestMethod([Frozen]Mock<IFoo> fooMock, MyController sut)
{
   // At this point you may setup expectation(s) on the fooMock.
   // The sut instance now uses the already created fooMock.
   // Verify any expectation(s).
}

您可以在this的博客文章中找到更多与AutoFixture、xUnit.net和Auto Mocking相关的链接和信息。

希望这能帮到您。


1
您可以使用“Freeze”方法来冻结一个类型的实例,这样当AutoFixture需要创建同一类型的实例时,它将重用已经创建的实例。您可以在此处找到更多关于此功能的信息。 - Nikos Baxevanis
1
请记住,如果您需要设置一个被请求类型的依赖项的模拟实例的期望值,那么只有在这种情况下才需要使用 Freeze。(当然,根据具体情况,您可能需要冻结多个类型实例。) - Nikos Baxevanis
3
示例1中,我们并不关心对IFoo模拟对象设置期望值。我们直接让AutoFixture创建一个MyController类型的实例。这将自动注入一个IFoo类型的模拟实例。在示例2中,我们确实想要设置期望值,因此我们手动创建了一个模拟实例,并使用_Freeze_将其冻结-告诉AutoFixture在请求MyController类型时重新使用已创建的实例。(如果我们不这样做,期望会失败,因为MyController将使用另一个实例-而不是我们设置期望的那个实例。) - Nikos Baxevanis
我一直在尝试使用你的示例,并想确认顺序似乎很重要?我尝试先创建控制器对象,然后再创建IFooMock,但我的单元测试失败了(因为我使用了Moq Verify并说该方法只应调用一次)。我认为它首先创建了自动模拟,然后创建了我告诉它要创建的模拟,从而导致每个方法被调用两次? - chobo2
2
是的,这是预期的,因为首先您请求了MyController类型(因此AutoFixture提供了IFoo依赖项的自动模拟实例),然后您创建了一个新的IFoo模拟对象(它是传递给MyController的不同实例)。当您需要在模拟对象上设置期望时,请在请求依赖于模拟对象的类型之前将其_Freeze_。这样,AutoFixture将_重用_已经创建的模拟对象,并且期望将成功。 - Nikos Baxevanis
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接