10

AutoFixture.AutoMoq パッケージで AutoFixture を使用すると、テスト対象を正しくテストするように構成されていないテストが見つかることがありますが、デフォルトの (Loose) Mock 動作のために問題が発見されることはありませんでした。

public interface IService
{
    bool IsSomethingTrue(int id);
}

void Main()
{
    var fixture = new Fixture()
        .Customize(new AutoMoqCustomization());
    var service = fixture.Freeze<Mock<IService>>();
    Console.WriteLine(service.Object.IsSomethingTrue(1)); // false
}

モックを Strict 動作で作成したいので、Setup()呼び出されると予想されるメソッドを呼び出さなければなりません。次のように、個々のモックごとにこれを行うことができます。

fixture.Customize<Mock<IService>>(c => c.FromFactory(() => new Mock<IService>(MockBehavior.Strict)));

しかし、AutoMoqCustomization() およびさまざまなISpecimenBuilder実装のソース コードをくまなく調べた後、すべてのモックを厳密な動作で初期化するための最善の方法についてかなり迷っています。このフレームワークは非常に柔軟で拡張可能であるように見えるので、これを行う簡単な方法があると確信していますが、方法がわかりません。

4

2 に答える 2

7

そのようなことを可能にする単純な組み込み機能はありませんが、それほど難しくはないはずです。

基本的にMockConstructorQuery、値を受け取るコンストラクターを呼び出すように変更してMockBehavior、 を渡す必要がありMockBehavior.Strictます。

現在、でその動作を変更することはできませんが、そのクラスはわずか 9 ~ 10 行のコードであるため、開始点としてを使用しMockConstructorQueryて実装する新しいクラスを作成できるはずです。IMethodQueryMockConstructorQuery

同様に、 AutoMoqCustomizationICustomizationとほぼ同じことを行うカスタムも作成する必要がありますが、唯一の例外は、 の代わりに厳密なモック構成でカスタムを使用することです。これは、さらに 7 行のコードを記述する必要があります。IMethodQueryMockConstructorQuery

とはいえ、私の経験では、厳密なモックを使用することは悪い考えです。テストが脆くなり、「壊れた」テストの修正に多くの時間を浪費することになります。これをしないことをお勧めすることしかできませんが、今警告しました。それはあなたの足です。

于 2015-12-03T20:37:45.750 に答える
3

興味のある方は、@MarkSeemann の返信をコードに変換したものを以下に示します。すべてのユースケースをカバーしているわけではなく、十分にテストされていないと確信しています。しかし、それは良い出発点になるはずです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Moq;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Ploeh.AutoFixture.Kernel;

namespace ConsoleApplication1
{
    public class StrictAutoMoqCustomization : ICustomization
    {
        public StrictAutoMoqCustomization() : this(new MockRelay()) { }

        public StrictAutoMoqCustomization(ISpecimenBuilder relay)
        {
            // TODO Null check params
            Relay = relay;
        }

        public ISpecimenBuilder Relay { get; }

        public void Customize(IFixture fixture)
        {
            // TODO Null check params
            fixture.Customizations.Add(new MockPostprocessor(new MethodInvoker(new StrictMockConstructorQuery())));
            fixture.ResidueCollectors.Add(Relay);
        }
    }

    public class StrictMockConstructorMethod : IMethod
    {
        private readonly ConstructorInfo ctor;
        private readonly ParameterInfo[] paramInfos;

        public StrictMockConstructorMethod(ConstructorInfo ctor, ParameterInfo[] paramInfos)
        {
            // TODO Null check params
            this.ctor = ctor;
            this.paramInfos = paramInfos;
        }

        public IEnumerable<ParameterInfo> Parameters => paramInfos;

        public object Invoke(IEnumerable<object> parameters) => ctor.Invoke(parameters?.ToArray() ?? new object[] { });
    }

    public class StrictMockConstructorQuery : IMethodQuery
    {
        public IEnumerable<IMethod> SelectMethods(Type type)
        {
            if (!IsMock(type))
            {
                return Enumerable.Empty<IMethod>();
            }

            if (!GetMockedType(type).IsInterface && !IsDelegate(type))
            {
                return Enumerable.Empty<IMethod>();
            }

            var ctor = type.GetConstructor(new[] { typeof(MockBehavior) });

            return new IMethod[]
            {
                new StrictMockConstructorMethod(ctor, ctor.GetParameters())
            };
        }

        private static bool IsMock(Type type)
        {
            return type != null && type.IsGenericType && typeof(Mock<>).IsAssignableFrom(type.GetGenericTypeDefinition()) && !GetMockedType(type).IsGenericParameter;
        }

        private static Type GetMockedType(Type type)
        {
            return type.GetGenericArguments().Single();
        }

        internal static bool IsDelegate(Type type)
        {
            return typeof(MulticastDelegate).IsAssignableFrom(type.BaseType);
        }
    }
}

使用法

var fixture = new Fixture().Customize(new StrictAutoMoqCustomization());
于 2016-04-27T04:54:53.107 に答える