0

MVCの作業を行ってからしばらく経ちましたので、何かが足りないことを願っています。「Business」という名前のDTOを編集するだけのテストおよびコントローラーアクションを作成しようとしています。

コントローラのアクション:

[HttpPost]
public ActionResult Edit(string id, Business business)
{
    try
    {
        var model = _businessRepository.Get(id);

        if (model != null)
        {
            UpdateModel(model);

            if (ModelState.IsValid)
            {
                _businessRepository.Save(model);
            }
            else
            {
                return View(business);
            }
        }

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

テスト:

[TestMethod]
public void Edit_Post_Action_Updates_Model_And_Redirects()
{
    // Arrange
    var mockBusinessRepository = new Mock<IBusinessRepository>();
    var model = new Business { Id = "1", Name = "Test" };
    var expected = new Business { Id = "1", Name = "Not Test" };

    // Set up result for business repository
    mockBusinessRepository.Setup(m => m.Get(model.Id)).Returns(model);
    mockBusinessRepository.Setup(m => m.Save(expected)).Returns(expected);
    var businessController = new BusinessController(mockBusinessRepository.Object);

    // Act
    var result = businessController.Edit(model.Id, expected) as RedirectToRouteResult;

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(result.RouteValues["action"], "Index");
    mockBusinessRepository.VerifyAll();
}

例外を与えている行は、コントローラーのUpdateModel()です。例外の詳細は次のとおりです。

「値をnullにすることはできません。パラメーター名:controllerContext」

4

5 に答える 5

1

そのControllerContextを設定するために通常使用するGistのコードがあります。コードは、もともとハンゼルマンのブログから取られた修正バージョンです。

https://gist.github.com/1578697(MvcMockHelpers.cs)

于 2012-04-11T13:38:11.497 に答える
1

コントローラコンテキストを設定します

以下は私が取り組んでいるプロジェクトのコードスニペットです。

public class TestBase
    {
        internal Mock<HttpContextBase> Context;
        internal Mock<HttpRequestBase> Request;
        internal Mock<HttpResponseBase> Response;
        internal Mock<HttpSessionStateBase> Session;
        internal Mock<HttpServerUtilityBase> Server;
        internal GenericPrincipal User;

            public void SetContext(Controller controller)
            {
              Context = new Mock<HttpContextBase>();
              Request = new Mock<HttpRequestBase>();
              Response = new Mock<HttpResponseBase>();
              Session = new Mock<HttpSessionStateBase>();
              Server = new Mock<HttpServerUtilityBase>();
       User = new GenericPrincipal(new GenericIdentity("test"), new string[0]);

              Context.Setup(ctx => ctx.Request).Returns(Request.Object);
              Context.Setup(ctx => ctx.Response).Returns(Response.Object);
              Context.Setup(ctx => ctx.Session).Returns(Session.Object);
              Context.Setup(ctx => ctx.Server).Returns(Server.Object);
              Context.Setup(ctx => ctx.User).Returns(User);

              Request.Setup(r => r.Cookies).Returns(new HttpCookieCollection());
              Request.Setup(r => r.Form).Returns(new NameValueCollection());
      Request.Setup(q => q.QueryString).Returns(new NameValueCollection());
              Response.Setup(r => r.Cookies).Returns(new HttpCookieCollection());

              var rctx = new RequestContext(Context.Object, new RouteData());
controller.ControllerContext = new ControllerContext(rctx, controller);
            }
}

次に、テストで次のことを調整できます。

//Arrange
SetContext(_controller);
Context.Setup(ctx => ctx.Request).Returns(Request.Object);

ModelStateエラーを使用してメソッドをテストする場合は、次を追加します。

_controller.ModelState.AddModelError("Name", "ErrorMessage");
于 2012-04-11T13:40:17.407 に答える
0

あなたはあなたのためにをモックする必要がありControllerContextますBusinessController

この質問またはこれを参照してください。

于 2012-04-11T13:26:10.090 に答える
0

UpdateModelの代わりにAutomapperを使用することで、私が望むものを何とか手に入れることができました。

自動マッパーの初期化に追加しました(IPersistableはすべてのDTOのインターフェイスです):

Mapper.CreateMap<IPersistable, IPersistable>().ForMember(dto => dto.Id, opt => opt.Ignore());

次に、コントローラーのアクションを次のように変更しました。

[HttpPost]
public ActionResult Edit(string id, Business business)
{
    try
    {
        var model = _businessRepository.Get(id);

        if (model != null)
        {
            Mapper.Map(business, model);

            if (ModelState.IsValid)
            {
                _businessRepository.Save(model);
            }
            else
            {
                return View(business);
            }
        }

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

そして私のテストを次のように変更しました:

[TestMethod]
public void Edit_Post_Action_Updates_Model_And_Redirects()
{
    // Arrange
    var mockBusinessRepository = new Mock<IBusinessRepository>();
    var fromDB = new Business { Id = "1", Name = "Test" };
    var expected = new Business { Id = "1", Name = "Not Test" };

    // Set up result for business repository
    mockBusinessRepository.Setup(m => m.Get(fromDB.Id)).Returns(fromDB);
    mockBusinessRepository.Setup(m => m.Save(It.IsAny<Business>())).Returns(expected);
    var businessController = new BusinessController(mockBusinessRepository.Object) {ControllerContext = new ControllerContext()};

    //Act
    var result = businessController.Edit(fromDB.Id, expected) as RedirectToRouteResult;

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(result.RouteValues["action"], "Index");
    mockBusinessRepository.VerifyAll();
}
于 2012-04-11T17:06:07.103 に答える
0

同じ問題が発生し、スタックトレースを使用してこれをValueProviderに固定しました。コントローラーによって使用される基になるオブジェクトの一部をモックするための上記のAndrewの回答に基づいて、次のようにValueProviderもモックすることで、null値の例外を解決することができました。

var controller = new MyController();

// ... Other code to mock objects used by controller ...

var mockValueProvider = new Mock<IValueProvider>();
controller.ValueProvider = mockValueProvider.Object;

// ... rest of unit test code which relies on UpdateModel(...)
于 2016-01-13T09:57:46.290 に答える