6

問題

私は、他の多くのサービスを利用するかなり大きなアプリケーションを持っています。テスト シナリオでは、単体テストをサード パーティのシステムに依存させたくないので、サービスをフェイクやモックなどに置き換えたいと考えています。

私はすでにほとんどの大変な作業を行っており、具体的なサービスをIService. 具体的な Service は 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...");
}

これは私が基本的に欲しいものを示しています。インターフェイスで指定されたタイプのランダムなものを返すメソッドを使用して、自動フィクスチャに動的プロキシオブジェクトを作成してもらいたいだけです...

ここでは 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、ランダムな文字列 (デフォルトでは GUID) を持つ budsResult です。 .. (それらは外部の SOAP サービスなどであり、それを助けることはできません) すべてを手動で設定したくありません。一般的な解決策があれば、それは素晴らしいことです...

すべてを手動で設定することで機能するファクトリの実装

お気づきかもしれませんが、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...");
}

これは少し混乱しているようで、これはかなり小さなインターフェースです。実際のサービスは何百ものメソッドを含む、何層もの深さがあります。

特定の条件を必要とするコード内のメソッドについては、明らかにこれらの条件を手動で設定しますが、それ以外はすべてデフォルトでランダム値にする必要があります。ランダムなオブジェクトを大量に生成すると、ファジー テストも少し可能になります。

この手動設定をすべて行わずに、ランダム オブジェクトを自動的に生成する方法はありますか?

4

1 に答える 1

3

ファクトリは必要ありませんし、インターフェース内のすべてのメソッドをセットアップする必要もありません。私が正しく理解している場合は、Fixtureを使用して、そのプロキシで呼び出すすべてのメソッドに対してランダムな値を返すプロキシを作成するだけです。AutoMoqCustomizationを使用する代わりにAutoConfiguredMoqCustomizationを使用します。これはすべて、Fixture.AutoMoq という nuget パッケージに含まれています。

class Program
{
    static void Main(string[] args)
    {
    }
}

[TestFixture]
public class program
{
    [Test]
    public void some_test()
    {
        var fixture = new Fixture();
        fixture.Customize(new AutoConfiguredMoqCustomization());

        var simpleServices = fixture.CreateMany<ISimpleService>();

        foreach (var simpleService in simpleServices)
        {
            string randomString = simpleService.Buzz("hello");
            int randomInt = simpleService.Fizz(15);
        }
    }
}

public interface ISimpleService
{
    int Fizz(int input);

    string Buzz(string input);
}
于 2015-09-07T04:47:10.927 に答える