2016-04-14 28 views
2

私はコマンドライン引数に依存するいくつかの機能を持っており、異なる引数は異なる結果につながるはずです。ユニットテストの "Simulate"コマンドライン引数

私はこの引数を直接 "シミュレート"できません。何らかのチェーン依存関係があります。ビューモデルに依存するいくつかの追加クラスに依存するxamlコントロールをユニットテストする必要があります。コマンドライン引数はEnvironment.GetCommandLineArgsを使用しています。この最後のクラスに直接影響して、GetCommandLineArgsの代わりに手動で引数を設定することはできません。

私は知りたいのですが、特定の単体テストで返すような戻り値を作成する方法がありますか?Environment.GetCommandLineArgs

+1

これまでに試したコードを投稿できますか? – ManoDestra

+0

Moqを使用しようとしましたか?任意のメソッドが必要なものを返すようにすることができます。 – Wjdavis5

+0

@ Wjdavis5私は、インターフェイスではなく、実際のクラスを模擬しようとした経験がありませんでした。しかし、いくつかの異なる解決策が出てきました。私は実際にユニットテストしているロジックを1に変更しました。これはmoqに適用できます。 – lentinant

答えて

2

あなたはEnvironment.GetCommandLineArgs抽象的に必要とするか、最終的には何かの後ろにそれを呼んでいる今まで何が最終的に

public class CommandInterface : ICommandLineInterface { 
    public string[] GetCommandLineArgs() { 
     return Environment.GetCommandLineArgs(); 
    } 
} 

のような具象クラスで実装することができ、使用して試験することができる

public interface ICommandLineInterface { 
    string[] GetCommandLineArgs(); 
} 

を模擬することができますMoqおよびFluentAssertions

[TestMethod] 
public void Test_Should_Simulate_Command_Line_Argument() { 
    // Arrange 
    string[] expectedArgs = new[] { "Hello", "World", "Fake", "Args" }; 
    var mockedCLI = new Mock<ICommandLineInterface>(); 
    mockedCLI.Setup(m => m.GetCommandLineArgs()).Returns(expectedArgs); 
    var target = mockedCLI.Object; 

    // Act 
    var args = target.GetCommandLineArgs(); 

    // Assert 
    args.Should().NotBeNull(); 
    args.Should().ContainInOrder(expectedArgs); 

} 
+0

非常に良いアイデア! +1 –

+0

最後に、私はこのことを正確に行いました。 – lentinant

1

環境変数を扱っているので、外部依存関係を1つのEnvironmentHelperクラスにラップしてから、依存関係を注入するのはなぜですか?ここで

は私の提案です:ソースコードで

public static string[] GetFakeEnvironmentCommandLineArgs() 
{ 
    return new string[] { "arg1", "arg2" }; 
} 

:あなたのユニットテストコードで

EnvironmentHelper envHelper = new EnvironmentHelper(Environment.GetCommandLineArgs); 
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs(); 

ここ

public class EnvironmentHelper 
{ 
    Func<string[]> getEnvironmentCommandLineArgs; 

     // other dependency injections can be placed here 

     public EnvironmentHelper(Func<string[]> getEnvironmentCommandLineArgs) 
     { 
      this.getEnvironmentCommandLineArgs = getEnvironmentCommandLineArgs; 
     } 

     public string[] GetEnvironmentCommandLineArgs() 
     { 
      return getEnvironmentCommandLineArgs(); 
     } 
} 

はモック方法であり、

EnvironmentHelper envHelper = new EnvironmentHelper(GetFakeEnvironmentCommandLineArgs); 
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs(); 
+0

@Nkosiは編集に感謝します。私は他の読者の混乱を引き起こしたくないので、私は最後のコメントを削除しました。 –

0

ユニットテスト可能なものが必要な場合は、実装と少なくとも同じ厳密な抽象に依存する必要があります。

通常、クラスのコンストラクタまたはプロパティメソッドを使用して依存関係を取得します。あなたのクラスの消費者は、コンパイル時に依存関係が何であるか知っているので、コンストラクタが一般的に好まれます。

public void int Main(string[] args) 
{ 
    // Validate the args are valid (not shown). 

    var config = new AppConfig(); 
    config.Value1 = args[0]; 
    config.Value2 = int.Parse(args[1]); 
    // etc.... 
} 

public class MyService() 
{ 
    private AppConfig _config; 

    public MyService(AppConfig config) 
    { 
     this._config = config; 
    } 
} 

通常、データはシリアル化可能なため、設定オブジェクトはインターフェイスの背後に置かれません。それがメソッドを持たない限り、私はoverride -dの振る舞いを持つサブクラスに置き換える必要はありません。また、私はちょうどnew私のテストでそれを直接することができます。

また、コマンドライン引数そのものをサービスに抽象化したいと思ったときに、コマンドラインの背後にあることを知る必要があるのはなぜですか?私が得た最も近いものは、簡単な解析のためにPowerArgsを使用していますが、私はMainでそれを消費します。私が普通にやっていることは、コマンドライン引数でWebサーバーのポート番号を読み取るようなものです(私は、同じマシン上でWebサーバーの複数のコピーを実行できるように、アプリケーションのユーザーに選択させます私はデバッグしている間にポートを競合しないで自動化されたテストを実行できます)、それらを直接私のMainクラスで解析してください。私のWebサーバーでは、解析されたコマンドライン引数、この場合はintに依存しています。そうすれば、設定がコマンドラインから来ているということは無関係です。後でApp.configファイルに移動できます(基本的にはプロセスのライフサイクルに縛られています)。 configSourceファイル。

一般的なコマンドラインの抽象度に依存するのではなく(純粋なままにしておけば、各サービスの消費は再解析する必要があります)、私は通常、強く型付けされたオブジェクトにコマンドラインとApp.configの依存関係を抽象化します - アプリレベルのコンフィグクラスとテストレベルのコンフィグクラスがあり、必要に応じて複数のコンフィグレーションオブジェクトを導入する必要があります(アプリはこれを気にする必要はありませんが、E2EテストインフラストラクチャではApp.configの別の部分にこれが必要です:クライアントの静的ファイルはどこから取得するのですか?テスト環境や開発環境でビルドスクリプトを取得して、index.htmlファイルの自動生成/自動更新などを行います)。

0

Typemock Isolatorを使用すると、はるかに簡単に操作できます。 これはインターフェイスだけでなく模擬することができます。

Environment.GetCommandLineArgs()のモック
[TestMethod, Isolated] 
public void TestFakeArgs() 
{ 
    //Arrange 
    Isolate.WhenCalled(() => Environment.GetCommandLineArgs()).WillReturn(new[] { "Your", "Fake", "Args" }); 

    //Act 
    string[] args = Environment.GetCommandLineArgs(); 

    //Assert 
    Assert.AreEqual("Your", args[0]); 
    Assert.AreEqual("Fake", args[0]); 
    Assert.AreEqual("Args", args[0]); 
} 

1行だけを取った:見てみましょう

Isolate.WhenCalled(() => Environment.GetCommandLineArgs()).WillReturn(new[] { "Your", "Fake", "Args" }); 

そして、あなたは新しいインターフェイスを作成するために、生産、コードを変更する必要はありません。

希望すると助かります!

+0

「モック・エブリシング:15日間試用」 –

+0

ニース)しかし、あなたが知っていることは、購入する価値のあるものがいくつかあります。それは私にたくさんのお金と時間を節約しました – Eva

+0

私はそれが必ずしも一部の人々のために買う価値はなかったと示唆しようとしていませんでした(あなたのMSDNがFakesをサポートしていれば、 )。この質問の今後の読者は、ツールのライセンスに何らかの理由で投資する手段を必ずしも持っていないので、リンクをクリックして時間を無駄にしないようにしました。将来の読者の利益のために、その情報をあなたの答えに組み込むことは価値があるかもしれません。 –

関連する問題