11

Indexコントローラーのアクションをテストしようとしています。このアクションは、AutoMapperを使用してドメインCustomerオブジェクトをビュー モデルにマップしますTestCustomerFormIndexこれは機能しますが、アクションから受け取った結果をテストする最良の方法について心配しています。

コントローラーの index アクションは次のようになります。

public ActionResult Index()
{
    TestCustomerForm cust = Mapper.Map<Customer,
        TestCustomerForm>(_repository.GetCustomerByLogin(CurrentUserLoginName));

    return View(cust);
}

そして、TestMethod次のようになります。

[TestMethod]
public void IndexShouldReturnCustomerWithMachines()
{
    // arrange
    var customer = SetupCustomerForRepository(); // gets a boiler plate customer
    var testController = CreateTestController();

    // act
    ViewResult result = testController.Index() as ViewResult;

    // assert
    Assert.AreEqual(customer.MachineList.Count(),
        (result.ViewData.Model as TestCustomerForm).MachineList.Count());
}

CreateTestController私が使用する方法では、Rhino.Mocks顧客リポジトリをモックし、顧客を返すように設定しますSetupCustomerForRepositoryIndexこのようにして、アクションが を呼び出すと、リポジトリが目的の顧客を返すことがわかります_repository.GetCustomerByLogin(CurrentUserLoginName)。したがって、等しい数を主張することは、を満たすのに十分であると考えていIndexShouldReturnCustomerWithMachinesます。

それはすべて、私が何をテストすべきかについて懸念していると言いました.

  1. をキャストするのはおこがましいようresult.ViewData.Model as TestCustomerFormです。これは本当に問題ですか?この場合、私は本当にテスト駆動開発を行っているわけではなく、テストを満たすために特定の実装を当てにしているように見えるため、これは私にとって懸念事項です。
  2. 正しいマッピングを確認するためのより適切なテストはありますか?
  3. からマップされた各プロパティをテストする必要がありますTestCustomerFormか?
  4. もっと一般的なコントローラ アクション テストを行う必要がありますか?
4

2 に答える 2

15

これが、AutoMapper をカスタム ActionResult または ActionFilter に移動した理由の 1 つです。ある時点で、Foo を FooDto にマップしたことだけをテストしたいだけで、必ずしも実際のマッピングをテストする必要はありません。AutoMapper をレイヤーの境界 (コントローラーとビューの間など) に移動することで、AutoMapper に何をするように指示しているかをテストすることができます。

これは、ViewResult のテストに似ています。ビューがレンダリングされたことをコントローラーからテストするのではなく、MVC にそのようなビューをレンダリングするように指示したことをテストします。アクションの結果は次のようになります。

public class AutoMapViewResult : ActionResult
{
    public Type SourceType { get; private set; }
    public Type DestinationType { get; private set; }
    public ViewResult View { get; private set; }

    public AutoMapViewResult(Type sourceType, Type destinationType, ViewResult view)
    {
        SourceType = sourceType;
        DestinationType = destinationType;
        View = view;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var model = Mapper.Map(View.ViewData.Model, SourceType, DestinationType);

        View.ViewData.Model = model;

        View.ExecuteResult(context);
    }
}

ベース コントローラー クラスのヘルパー メソッドを使用する場合:

protected AutoMapViewResult AutoMapView<TDestination>(ViewResult viewResult)
{
    return new AutoMapViewResult(viewResult.ViewData.Model.GetType(), typeof(TDestination), viewResult);
}

これにより、コントローラーは、実際のマッピングを実行する代わりに、マッピング先/マッピング元のみを指定するようになります:

public ActionResult Index(int minSessions = 0)
{
    var list = from conf in _repository.Query()
                where conf.SessionCount >= minSessions
                select conf;

    return AutoMapView<EventListModel[]>(View(list));
}

この時点で、実際にマッピングを実行する必要はなく、「この Foo オブジェクトをこの宛先 FooDto タイプにマッピングしていることを確認する」ことだけをテストする必要があります。

編集:

テスト スニペットの例を次に示します。

var actionResult = controller.Index();

actionResult.ShouldBeInstanceOf<AutoMapViewResult>();

var autoMapViewResult = (AutoMapViewResult) actionResult;

autoMapViewResult.DestinationType.ShouldEqual(typeof(EventListModel[]));
autoMapViewResult.View.ViewData.Model.ShouldEqual(queryResult);
autoMapViewResult.View.ViewName.ShouldEqual(string.Empty);
于 2010-06-21T12:23:26.577 に答える
2

AutoMapper抽象化を導入することで、コントローラーとの間の結合をおそらく分離します。

public interface IMapper<TSource, TDest>
{
    TDest Map(TSource source);
}

public CustomerToTestCustomerFormMapper: IMapper<Customer, TestCustomerForm>
{
    static CustomerToTestCustomerFormMapper()
    {
        // TODO: Configure the mapping rules here
    }

    public TestCustomerForm Map(Customer source)
    {
        return Mapper.Map<Customer, TestCustomerForm>(source);
    }
}

次に、これをコントローラーに渡します。

public HomeController: Controller
{
    private readonly IMapper<Customer, TestCustomerForm> _customerMapper;
    public HomeController(IMapper<Customer, TestCustomerForm> customerMapper)
    {
        _customerMapper = customerMapper;
    }

    public ActionResult Index()
    {
        TestCustomerForm cust = _customerMapper.Map(
            _repository.GetCustomerByLogin(CurrentUserLoginName)
        );
        return View(cust);
    }
}

単体テストでは、お気に入りのモック フレームワークを使用して、このマッパーをスタブ化します。

于 2010-06-21T06:30:36.280 に答える