1

以下のメソッドでいくつかの単体テストを実行したいと思います。モック化されたインターフェイス ( vehicleObject ) をProcessVehiclesに渡していますが、渡されるとすぐに、DeterminVehicleTypeによって再割り当てされるため、モック化されたオブジェクトは役に立ちません。私の最初のアイデアは、ブール値を作成して、 DeterminVehicleTypeを実行し、それをパラメーターとして追加する必要があるかどうかを判断することですが、それは非常に面倒に聞こえます。これを回避するより良い方法はありますか?

Mock オブジェクトが注入されるメソッド:

public void ProcessVehicles(ICarObject CarObject)
{
    IObject vehicleObject = DetermineVehicleType(carObject);
    vehicleObject.ProcessVehicle(carObject);
}

元のコード:

public void ProcessVehicles()
{
    IObject vehicleObject = DetermineVehicleType(carObject);
    vehicleObject.ProcessVehicle(carObject);
}

注:クラスが実際に使用されるときに null ではない可能性があるため、DetermineVehicleTypeを呼び出す前に vehicleObject が null であるかどうかを確認できません。長期的には、完全なリファクタリングが答えになるかもしれませんが、現時点では、それは私が探している答えではないかもしれません。

メソッド IdentifyVehicleType は非公開です

注: コードの匂いがあることはわかっています。これは、現在動作しているレガシー コードです。私はそれを変更せずにテストしたいので、見栄えが良く、本番環境で壊れます。完全なリファクタリングが唯一のオプションかもしれませんが、モック ツールを使用した別のソリューションがないことを確認したいだけです。

4

2 に答える 2

3

どのアクセス修飾子がDetermineVehicleType持っていますか? そのメソッドをスタブ化して、モックしたインターフェイスを返すようにすることもできます (Roy Osherove はこれabstract test driver patternを と呼んでいると思います)。そうでなければ、これはリファクタリングの最有力候補のように見えます:)

コードをリファクタリングするには、次のようにします

まず、メソッドのシグネチャを変更します

protected virtual IObject DetermineVehicleType(CarObject obj)
{
    //Do whatever you normally do
}

次に、テストで、上記のクラスからスタブを作成し、渡されたものに関係なく、スタブ化された IObject を返すようにしますCarObject。クラスから継承してスタブ クラスを手動で作成するか、次のようなものを使用できます。これを達成するための MOQ。これについてもう少し詳しく説明する必要がある場合はお知らせください。

ただし、別の注意事項:

これをリファクタリングするより良い方法は、単純に を に渡すIObjectことProcessVehiclesです。この例から、メソッドが処理以上のことを行っているSRP違反がここにあることがわかります。ProcessVehiclesしかし、おそらくそれはこの単純化された例からのものです

完全な実装の更新

    [Test]
    public void TestMethod()
    {
        var testerStub = new TesterStub();
        testerStub.ProcessVehicles();
        //Assert something here
    }

    public class TesterStub : Tester
    {
        public override IObject DetermineVehicleType(CarObject obj)
        {
            var mockObject = new Mock<IObject>();
            mockObject.Setup(x => x.SomeMethod).Returns(Something);
            return mockObject.Object;
        }
    }

    public class Tester
    {
        protected virtual IObject DetermineVehicleType(CarObject obj)
        {
            return new ObjectTester();
        }

        public void ProcessVehicles()
        {
            var carType = DetermineVehicleType(new CarObject());

        }
    }

    public class ObjectTester : IObject
    {
    }

    public interface IObject
    {
    }

    public class CarObject
    {
    }
于 2012-03-21T19:26:01.103 に答える
1

私たちが非常に文字通りである場合、あなたのコードは臭いを示していると思います.

これを考慮してください: メソッドProcessVehiclesは、 と呼ばれるインスタンスのメソッドを呼び出しますDetermineVehicleType。あなたのクラスは何をしますか?そうですかProcess Vehicles、それともそうDetermine Vehicle Typeですか?文字通りに受け取ると、これは SRP に違反していることを示しています。あなたのクラスは複数の仕事をしようとしています。

これはおそらく、SRP がプライベート ヘルパー メソッドを承認していないことを意味します。一部のコメンテーターは、実際にこれが事実であると考えています。よくわかりません。いつものように、常識が鍵です。

このコードをリファクタリングする場合、クラスに のようなものIVehicleCategoryHelperを指定しDetermineVehicleTypeます。おそらく、これはそのコンストラクターを介して渡されるか、完全な Fat Dependency Injection を実装している場合は IFactory で、コンテキストに応じて必要なときにインスタンスが IVehicleCategoryHelper を取得できるようにします。

私が言ったことはすべて、ひとつまみの塩で考えてください。これが正しいアプローチであるとは必ずしも信じていません。最終的にはあなた次第です。

于 2012-03-21T19:57:03.653 に答える