6

私はユニットテストを学んでいます。nunitとrhinoモックを使用してこのメ​​ソッドをユニットテストする方法は?

public ActionResult PrintCSV(Byte[] bytes, string fileName)
{
    var file = File(bytes, "application/vnd.ms-excel");
    var cd = new System.Net.Mime.ContentDisposition()
    {
        CreationDate = DateTime.Now,
        FileName = fileName,
        Inline = false
    };
    Response.AppendHeader("Content-Disposition", cd.ToString());
    return file;
}
4

1 に答える 1

8

HttpContext をモックする必要があります。以下に例を示します (これは MSTest ですが、NUnit に移植するのはそれほど面倒なことではないと思います。必要なのは、いくつかの属性の名前を変更することだけです)。

[TestMethod]
public void PrintCSV_Should_Stream_The_Bytes_Argument_For_Download()
{
    // arrange 
    var sut = new HomeController();
    var bytes = new byte[] { 1, 2, 3 };
    var fileName = "foobar";
    var httpContext = MockRepository.GenerateMock<HttpContextBase>();
    var response = MockRepository.GenerateMock<HttpResponseBase>();
    httpContext.Expect(x => x.Response).Return(response);
    var requestContext = new RequestContext(httpContext, new RouteData());
    sut.ControllerContext = new ControllerContext(requestContext, sut);

    // act
    var actual = sut.PrintCSV(bytes, fileName);

    // assert
    Assert.IsInstanceOfType(actual, typeof(FileContentResult));
    var file = (FileContentResult)actual;
    Assert.AreEqual(bytes, file.FileContents);
    Assert.AreEqual("application/vnd.ms-excel", file.ContentType);
    response.AssertWasCalled(
        x => x.AppendHeader(
            Arg<string>.Is.Equal("Content-Disposition"),
            Arg<string>.Matches(cd => cd.Contains("attachment;") && cd.Contains("filename=" + fileName))
        )
    );
}

ご覧のとおり、テストをセットアップするための配管コードが少しあります。個人的にはMvcContrib.TestHelperを使用しています。これは、この配管コードの多くを簡素化し、テストをより読みやすくするためです。これをチェックしてください:

[TestClass]
public class HomeControllerTests : TestControllerBuilder
{
    private HomeController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        this.sut = new HomeController();
        this.InitializeController(this.sut);
    }

    [TestMethod]
    public void PrintCSV_Should_Stream_The_Bytes_Argument_For_Download()
    {
        // arrange 
        var bytes = new byte[] { 1, 2, 3 };
        var fileName = "foobar";

        // act
        var actual = sut.PrintCSV(bytes, fileName);

        // assert
        var file = actual.AssertResultIs<FileContentResult>();
        Assert.AreEqual(bytes, file.FileContents);
        Assert.AreEqual("application/vnd.ms-excel", file.ContentType);
        this.HttpContext.Response.AssertWasCalled(
            x => x.AppendHeader(
                Arg<string>.Is.Equal("Content-Disposition"),
                Arg<string>.Matches(cd => cd.Contains("attachment;") && cd.Contains("filename=" + fileName))
            )
        );
    }
}

初期化フェーズ、テスト中のメソッドの実際の呼び出し、およびアサーションをすぐに確認できるため、テストはより明確になりました。

備考: 以上のことから、バイト配列をクライアントにストリーミングするためだけに引数として受け取るコントローラ アクションのポイントがよくわかりません。つまり、それを呼び出すには、クライアントが既にファイルを持っている必要があるので、ポイントは何ですか? しかし、それは単なる説明のためだったと思います。実際のメソッドでは、バイト配列は引数として渡されませんが、外部依存関係からコントローラー アクション内で取得されます。この場合、この依存関係をモックすることもできます (もちろん、レイヤーを適切に設計し、それらが十分に弱く結合されていると仮定します)。

于 2013-01-16T14:34:32.130 に答える