コントローラークラスのテスト

チュートリアル: ASP.NET MVC での TDD の使用

上記リンク先からダウンロードできるサンプルソースはMVC2のときのものですが、十分参考になります。
コントローラークラスに対するテストを勘違いしていたところがあったので、自コメント付けてソースを丸々貼り付け。
コントローラークラスのテストは正直いらないんじゃ?と思ってた(または優先度低い)。単体テストというよりは複合テスト?

また、テストの書き方も参考なりました。
  • 確認項目ごとにテストメソッドを定義する。
  • 同一メソッドに複数の仕様があり、それらを確認する必要があればそのぶんだけ、そのメソッドに対するテストが存在すべきである。
[TestClass]
public class HomeControllerTest {
  
  //ビュー名のテスト
  [TestMethod]
  public void Index_Get_AsksForIndexView() {
    // Arrange
    var controller = GetHomeController(new InMemoryContactRepository());
    // Act
    ViewResult result = controller.Index();
    // Assert
    Assert.AreEqual("Index", result.ViewName);
  }
  
  //ビューが持つモデル値のテスト
  [TestMethod]
  public void Index_Get_RetrievesAllContactsFromRepository() {
    // Arrange
    Contact contact1 = GetContactNamed(1, "Orlando", "Gee");
    Contact contact2 = GetContactNamed(2, "Keith", "Harris");
    InMemoryContactRepository repository = new InMemoryContactRepository();
    repository.Add(contact1);
    repository.Add(contact2);
    var controller = GetHomeController(repository);
  
    // Act
    var result = controller.Index();
  
    // Assert
    var model = (IEnumerable<Contact>)result.ViewData.Model;
    CollectionAssert.Contains(model.ToList(), contact1);
    CollectionAssert.Contains(model.ToList(), contact1);
  } 
  
  //情報追加するアクションメソッド呼び出し後のContactレコード追加確認
  [TestMethod]
  public void Create_Post_PutsValidContactIntoRepository() {
    // Arrange
    InMemoryContactRepository repository = new InMemoryContactRepository();
    HomeController controller = GetHomeController(repository);
    Contact contact = GetContactID_1();
  
    // Act
    controller.Create(contact);  //情報追加するアクションメソッド呼び出し
  
    // Assert
    IEnumerable<Contact> contacts = repository.GetAllContacts();
    Assert.IsTrue(contacts.Contains(contact));
  } 
  
  //リダイレクト先の確認
  //⇒前のテスト(Create_Post_PutsValidContactIntoRepository)と同じアクションメソッドに対するテストだが、
  //確認項目事にテストメソッドを作成している。以降もCreateメソッドに対するテストが続く。
  [TestMethod]
  public void Create_Post_ReturnsRedirectOnSuccess() {
    // Arrange
    HomeController controller = GetHomeController(new InMemoryContactRepository());
    Contact model = GetContactID_1();
  
    // Act
    var result = (RedirectToRouteResult)controller.Create(model);
  
    // Assert
    Assert.AreEqual("Index", result.RouteValues["action"]);
  }
  
  //モデル状態がエラーな状態でアクションメソッドを呼び出すテスト
  //Createアクションメソッドの仕様ではHttpGetなCreateビューが返されるので、それの確認を行っている。
  [TestMethod]
  public void Create_Post_ReturnsViewIfModelStateIsNotValid() {
    // Arrange
    HomeController controller = GetHomeController(new InMemoryContactRepository());
    // Simply executing a method during a unit test does just that - executes a method, and no more. 
    // The MVC pipeline doesn't run, so binding and validation don't run.
    controller.ModelState.AddModelError("", "mock error message");
    Contact model = GetContactNamed(1, "", "");
  
    // Act
    var result = (ViewResult)controller.Create(model);
  
    // Assert
    Assert.AreEqual("Create", result.ViewName);
  } 
  
  //アクションメソッドで例外を発生させるテスト
  [TestMethod]
  public void Create_Post_ReturnsViewIfRepositoryThrowsException() {
    // Arrange
    InMemoryContactRepository repository = new InMemoryContactRepository();
    Exception exception = new Exception();
    repository.ExceptionToThrow = exception;
    HomeController controller = GetHomeController(repository);
    Contact model = GetContactID_1();
  
    // Act
    var result = (ViewResult)controller.Create(model);
  
    // Assert
    Assert.AreEqual("Create", result.ViewName);
    ModelState modelState = result.ViewData.ModelState[""];
    Assert.IsNotNull(modelState);
    Assert.IsTrue(modelState.Errors.Any());
    Assert.AreEqual(exception, modelState.Errors[0].Exception);
  } 
  // </snippet7>
  
  Contact GetContactID_1() {
    return GetContactNamed(1, "Janet", "Gates");
  }
  
  Contact GetContactNamed(int id, string fName, string lName) {
    return new Contact
    {
      Id = id,
      FirstName = fName,
      LastName = lName,
      Phone = "710-555-0173",
      Email = "janet1@adventure-works.com"
    };
  
  }
  
  //コントローラーオブジェクトを生成する。
  private static HomeController GetHomeController(IContactRepository repository) {
    HomeController controller = new HomeController(repository);
  
    controller.ControllerContext = new ControllerContext()
    {
      Controller = controller,
      RequestContext = new RequestContext(new MockHttpContext(), new RouteData())
    };
    return controller;
  }
  
  
  //モックHttpContextクラス
  private class MockHttpContext : HttpContextBase {
    private readonly IPrincipal _user = new GenericPrincipal(new GenericIdentity("someUser"), null /* roles */);
  
    public override IPrincipal User {
      get {
        return _user;
      }
      set {
        base.User = value;
      }
    }
  }
}