2

次のシナリオがあります。

public void DoSomething(...)
{
   ...
   ClassA obj1 = new ClassA();
   ClassB obj2 = new ClassB();
   ClassC obj3 = new ClassC();
   ...
}

Dependency Inversion Principle を使用していた場合、インターフェースをモックでき、それが機能することを理解しています。問題は、これらのインスタンスが必要なのはこのメソッドだけであるため、クラス レベルでインスタンスを作成する意味がないことです。その上、一部のメソッドには 5 ~ 6 個のオブジェクト宣言があるため、これらをパラメーターとして渡すと、パラメーター リストが肥大化します。

Moq、NMock などを使用してこれらのクラス (共通のインターフェイスに基づいている) をモックする方法はありますか?

4

2 に答える 2

2

そのメソッドでこれらの型をインスタンス化するだけでよい場合は、それらをクラスに注入しないでください。

代わりに、一般的な解決策は、メソッドがインターフェイスを解決できるようにするファクトリを注入することです。

通常のアプローチは次のとおりです。

interface IMessageFactory
{
    IMessage CreateMessage(string text);   
}

class ConcreteMessageFactory : IMessageFactory
{
    IMessage CreateMessage(string text) { return new Message(text); }
}

class MockMessageFactory : IMessageFactory
{
    public IMessage CreateMessage(string text) { return new MockMessage(text); }
}


class MyClient
{
    private readonly IMessageFactory _msgFactory;

    public MyClient(IMessageFactory msgFactory)
    {
        _msgFactory = msgFactory;   
    }

    public void SendMessage(string text)
    {
        IMessage msg = _msgFactory.CreateMessage(text);
        msg.Send();
    }
}


//Usage:
new MyClient(new ConcreteMessageFactory());
//Mocking
new MyClient(new MockMessageFactory());

使用している DI フレームワークによっては、フレームワークによってこの方法が簡単になります。たとえば、Castle Windsor では、上記のインターフェイス ベースのファクトリとは対照的に、デリゲート ベースのファクトリを注入できます。

class MyClient
{
    private readonly Func<string, IMessage> _msgFactory;

    public MyClient(Func<string, IMessage> msgFactory)
    {
        _msgFactory = msgFactory;   
    }

    public void SendMessage(string text)
    {
        IMessage msg = _msgFactory(text);
        msg.Send();
    }
}

//Usage:
new MyClient(() => new Message());
//Mocking
new MyClient(() => new MockMessage());
于 2014-07-23T23:07:45.633 に答える
1

StructureMap のようなものを使用して作業を行うことができます。メソッドは次のようになります。

public void DoSomething(...)
{
   ...
   IClassA obj1 = ObjectFactory.GetInstance<IClassA>();
   IClassB obj2 = ObjectFactory.GetInstance<IClassB>();
   IClassC obj3 = ObjectFactory.GetInstance<IClassC>();
   ...
}

次に、通常、global.asax などでこのようにマップします。

        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<ClassA>();
            ...etc
        });

しかし、あなたのユニットテストのために

        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<UnitTestClassA>();
            ...etc
        });
于 2014-07-23T23:02:35.300 に答える