自动混合模拟接口以返回随机结果以用于测试目的

时间:2013-10-02 20:48:59

标签: c# unit-testing moq autofixture

问题

我有一个非常大的应用程序,它使用了许多其他服务。 对于测试场景,我不希望我的单元测试依赖于第三方系统,所以我想用假货或模拟或其他任何东西来替换服务。

我已经完成了大部分艰苦工作,并用IService取代了具体服务。具体的服务与DI框架连接

现在我想用随机生成的假货取代那些。

代码

示例服务的接口:

public interface ISimpleService
{
    int Fizz(int input);

    string Buzz(string input);
}

示例服务工厂的接口:

public interface ISimpleServiceFactory
{
    ISimpleService Create();
}

尽可能简化实施

public static void Main(string[] args)
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var service = fixture.Create<ISimpleService>();

    var fizzResult = service.Fizz(42);
    var buzzResult = service.Buzz("I'd like something random...");
}

这显示了我基本上想要的东西。我只想让autofixture为我创建一些动态代理对象,方法返回接口中指定类型的随机内容......

请注意,我在这里使用过AutoMoq,因为默认情况下Fixture不想从接口创建对象,但我也尝试过其他框架:FakeItEasy,AutoRhinoMock

解决方法

通过手动设置所有内容

实现这种方式
public static void Main(string[] args)
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var serviceMock = fixture.Create<Mock<ISimpleService>>();

    // These two lines below cause the magic now
   serviceMock.Setup(x => x.Fizz(It.IsAny<int>())).Returns(fixture.Create<int>());
   serviceMock.Setup(x => x.Buzz(It.IsAny<string>())).Returns(fixture.Create<string>());

    var service = serviceMock.Object;
    var fizzResult = service.Fizz(42);
    var buzzResult = service.Buzz("I'd like something random...");
}

这确实给了我想要的结果:带有随机int的fizzResult,带有随机字符串的buzzResult(默认为guid) 然而,这只是一个小例子,我的实际服务参考更大,有多达100个方法......(它们是外部肥皂服务等,无法帮助它) 我不想手动设置所有内容,如果这是一个通用的解决方案,那就太棒了......

通过手动设置所有内容来实现工厂的实现

所以,正如您可能已经注意到的那样,我还发布了一个ISimpleServiceFactory界面。这类似于实际情况,因为实际具体ISimpleService需要一堆配置。 所以,如果我们使用那种工作解决方案,我们就会来:

public static void Main(string[] args)
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var serviceFactoryMock = fixture.Create<Mock<ISimpleServiceFactory>>();

    var serviceMockDelegate = new Func<ISimpleService>(() =>
        {
            var serviceMock = fixture.Create<Mock<ISimpleService>>();
            serviceMock.Setup(x => x.Fizz(It.IsAny<int>())).Returns(fixture.Create<int>());
            serviceMock.Setup(x => x.Buzz(It.IsAny<string>())).Returns(fixture.Create<string>());

            return serviceMock.Object;
        });

    serviceFactoryMock.Setup(x => x.Create()).Returns(serviceMockDelegate);
    var service = serviceFactoryMock.Object.Create();

    var fizzResult = service.Fizz(42);
    var buzzResult = service.Buzz("I'd like something random...");
}

这似乎变得有点乱,这是一个非常小的界面。 实际的服务有很多层次,有100多种方法。

对于我的代码中需要特定条件的方法,我显然仍会手动设置这些条件,但默认情况下其他所有内容都应该是随机值。生成大量随机对象也允许进行一些模糊测试

有没有办法在没有设置所有手册的情况下自动生成随机对象?

1 个答案:

答案 0 :(得分:3)

您不需要工厂也不需要设置界面中的每个方法,如果我理解正确您只想使用 Fixture 来创建代理,该代理为每个方法返回随机值你在那个代理上调用。而不是使用 AutoMoqCustomization 使用 AutoConfiguredMoqCustomization 。这一切都在名为Fixture.AutoMoq的nuget包中。

getServer().getPluginManager().registerEvents