質問

私はテストとモックが初めてで、検証ロジックがModelStateエラーを正しく設定していることを確認するテストを作成しようとしています。

私が見ているのは、初めてチェックしたときに controller.ControllerContext.HttpContext.Request が設定されますが、その後は常に Request がnullであるということです。

これにより、MVCソースの* ValueProviderDictionary *クラスの PopulateDictionary メソッドでnull参照例外が発生します。これは、リクエストがnullでないことを確認せずにリクエストオブジェクトがそのメソッドで複数回アクセスされるためです。

これまでに遭遇した問題のいくつかを克服する方法を研究中に発見したいくつかのテクニックとヘルパーを一緒に接着しているので、この時点でどこで問題を導入したのか少しわかりません。

ここでモックオブジェクトを間違って使用していますか

テストの失敗

//Test
public void Test_FooController_OnActionExecuting_ShouldMapStateToAFooModel()
{
    //Arrange
    DataAccessFactoryMocks.MockAllDaos();

    var controller = new FooController();

    var testFormCollection = new NameValueCollection();
    testFormCollection.Add("foo.CustomerID", "3");
    testFormCollection.Add("_fooForm", SerializationUtils.Serialize(new FooModel()));

    var mockHttpContext = new MockHttpContext(controller, "POST", testFormCollection, null);

    //Accessor used to run the protected OnActionExecuting method in my controller
    var accessor = new FooControllerAccessor(controller);

    //Request is set, assertion passes
    Assert.IsNotNull(controller.ControllerContext.HttpContext.Request.Form);

    //Request is null when accessing the property a second time, assertion fails
    Assert.IsNotNull(controller.ControllerContext.HttpContext.Request.QueryString);

    //Act
    accessor.OnActionExecuting(new ActionExecutingContext(controller.ControllerContext, MockRepository.GenerateStub<ActionDescriptor>(), new Dictionary<string, object>()));

    //Assert
    Assert.That(controller.ModelState.IsValid == false);
}

テストヘルパー

//Test helper to create httpcontext and set controller context accordingly
public class MockHttpContext
{
    public HttpContextBase HttpContext { get; private set; }
    public HttpRequestBase Request { get; private set; }
    public HttpResponseBase Response { get; private set; }
    public RouteData RouteData { get; private set; }

    public MockHttpContext(Controller onController)
    {
        //Setup the common context components and their relationships
        HttpContext = MockRepository.GenerateMock<HttpContextBase>();
        Request = MockRepository.GenerateMock<HttpRequestBase>();
        Response = MockRepository.GenerateMock<HttpResponseBase>();

        //Setup the context, request, response relationship
        HttpContext.Stub(c => c.Request).Return(Request);
        HttpContext.Stub(c => c.Response).Return(Response);

        Request.Stub(r => r.Cookies).Return(new HttpCookieCollection());
        Response.Stub(r => r.Cookies).Return(new HttpCookieCollection());

        Request.Stub(r => r.QueryString).Return(new NameValueCollection());
        Request.Stub(r => r.Form).Return(new NameValueCollection());

        //Apply the context to the suppplied controller
        var rc = new RequestContext(HttpContext, new RouteData());
        onController.ControllerContext = new ControllerContext(rc, onController);
    }

    public MockHttpContext(Controller onController, string httpRequestType, NameValueCollection form, NameValueCollection querystring)
    {
    //Setup the common context components and their relationships
    HttpContext = MockRepository.GenerateMock<HttpContextBase>();
    Request = MockRepository.GenerateMock<HttpRequestBase>();
    Response = MockRepository.GenerateMock<HttpResponseBase>();

    //Setup request type based on parameter value
    Request.Stub(r => r.RequestType).Return(httpRequestType);

    //Setup the context, request, response relationship
    HttpContext.Stub(c => c.Request).Return(Request);
    HttpContext.Stub(c => c.Response).Return(Response);

    Request.Stub(r => r.Cookies).Return(new HttpCookieCollection());
    Response.Stub(r => r.Cookies).Return(new HttpCookieCollection());

    Request.Stub(r => r.QueryString).Return(querystring);
    Request.Stub(r => r.Form).Return(form);

    //Apply the context to the suppplied controller
    var rc = new RequestContext(HttpContext, new RouteData());
    onController.ControllerContext = new ControllerContext(rc, onController);
    }
}

MvcContrib.TestHelperを使用した作業テスト

    public void Test_FooController_OnActionExecuting_ShouldMapStateToAFooModel()
    {
        //Arrange
        DataAccessFactoryMocks.MockAllDaos();

        TestControllerBuilder builder = new TestControllerBuilder();

        builder.Form.Add("fooModel.CustomerID", "3");

        builder.HttpContext.Request.Stub(r => r.RequestType).Return("POST");

        FooController controller = builder.CreateController<FooController>();

        var accessor = new FooControllerAccessor(controller);

        //Act
        accessor.OnActionExecuting(new ActionExecutingContext(controller.ControllerContext, MockRepository.GenerateStub<ActionDescriptor>(), new Dictionary<string, object>()));

        //Assert
        Assert.IsFalse(controller.ModelState.IsValid);
    }
役に立ちましたか?

解決

ユニットに優れた MVCContrib TestHelper を使用することをお勧めしますRhino Mocksを使用してASP.NET MVCコントローラーをテストします。ユニットテストが大幅に簡素化され、読みやすさが向上します。

他のヒント

私があなたの質問から理解しているのは、ゴールがControllerContextの動作をテストしていないため、ControllerContextのモックをスタブオブジェクトに置き換えることもできるということです。また、FooControllerAccessorが必要なのはModelStateをアサートすることだけであるのに、なぜそうなるのかはよく分からないので、ここでは省略しました。

public void Test_FooController_OnActionExecuting_ShouldMapStateToAFooModel()
{
    // Arrange
    var action = new FooController()
        .Action("index")
        .RequestData(new Dictionary<string, object>()
        {
            {"foo.CustomerID", 3},
            {"_fooForm", new FooModel()}
        });

    //Act
    var modelState = action.ValidateRequest();

    //Assert
    Assert.That(modelState.IsValid == false);
}

このコードを使用するには、Xania.AspNet.Simulatorをインストールする必要があります(執筆時点でv1.4.0-beta5)Mvc4およびMvc5で動作します

  

PM &gt;インストールパッケージXania.AspNet.Simulator -Pre

その他の例については、次を確認してください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top