web-dev-qa-db-ja.com

DIを使用しない単体テスト

私は小さなASP.NET MVCプロジェクトを開始しています。ボード上の各タスクにはユニットテストが必要です。プロジェクトは小さく、処理が少ない数ページしかないため、DIを実装しないことにしました。 DIであるとの私の考えは、依存関係グラフを使用する大規模なプロジェクトに対するものです。

しかし、今はテストを書いているので、テストがより難しいことに気付きました。コンストラクターの注入は行われていないため、コントローラーアクションによって使用されているこれらのオブジェクトをモックするのは面倒です。

コンストラクターの注入がないためにアクションでインスタンス化されているオブジェクトがある場合、それらをモックしてテストできますか?

4
James

ここに質問があります:これはDIのように見えますか?

public class MyCar
{
    private IEngine _engine;

    public MyCar(IEngine engine)
    {
        _engine = engine;
    }

    public MyCar()
        : this(new MyV8Engine())
    {

    }
}

IS DI。Dependency Injectionとは、依存関係をオブジェクトに注入することであり、それを必要とするオブジェクトへの依存関係を新たに作成したり、依存関係を見つけたりするのではなく、 DIはフレームワークの使用ではなく、問題を解決する設計パターンです

小規模なアプリケーションがコンストラクタベースの注入とデフォルトのコンストラクタで新しいオブジェクトを使用することは非常に有効です。これをDIの例として見ない理由は、多くの場合、依存関係グラフがすぐに非常に大きく扱いにくくなり、アプリケーションの成長に伴ってDIフレームワークへの移行が急速に有利になるためです。

10
JDT

コンストラクターの注入がないためにアクションでインスタンス化されているオブジェクトがある場合、それらをモックしてテストできますか?

コードをリファクタリングして、別の保護されたメソッドにモックする必要のあるすべてのコードをカプセル化し、次に partial-mocks を使用してそのロジックを置き換えることができます。

例(Java)

元の

protected void moveFiles(File[] destFiles, File[] sourceFiles) {
    int pos = 0;
    while (pos < fileCount) {
        File sourceFile = sourceFiles[pos];
        File destFile = destFiles[pos];

        // do some processing. i.e. rename destFile if it already exists.

        // do the copy. the test should not execute this
        sourceFile.renameTo(destFile)
        pos++;
    }
}

リファクタリング:

protected void moveFiles(File[] destFiles, File[] sourceFiles) {
    int pos = 0;
    while (pos < fileCount) {
        File sourceFile = sourceFiles[pos];
        File destFile = destFiles[pos];

        // do some processing. i.e. rename destFile if it already exists.
        osFileMove(destFile, sourceFile);
        pos++;
    }
}

/** can be replaced by mock/stub in unittests */
protected boolean osFileMove(File destFile, File sourceFile) {
    return sourceFile.renameTo(destFile);
}

テストでは、osFileMoveを偽物で置き換えることができます(例ではJava org.mockito.Mockitoを使用しています)

import static org.mockito.Mockito.*;

FileCommands sut;
@Before
public void setup() {
    sut = spy(new FileCommands());
    doReturn(true).when(sut).osCreateDirIfNeccessary(any(File.class));
    doReturn(true).when(sut).osFileCopy(any(File.class), any(File.class));
    doReturn(true).when(sut).osFileMove(any(File.class), any(File.class));
    doReturn(true).when(sut).osDeleteFile(any(File.class));
}

後でiocを使用することにした場合は、os-spcificファイル操作osxXXXXを別のクラスとインターフェイスに移動できます。

3
k3b