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