当 Controller 通过单元测试实例化时 ModelState 为 null

ModelState null when Controller instantiated by unit test

我正在尝试对我的控制器进行单元测试,其中包含对 ModelState.IsValid 的检查,但出于某种原因,无论我做什么,我总是在任何地方尝试访问 ModelState(都在单元中测试和控制器功能)。

我到处检查人们是否只使用 ModelState.Clear()/.AddModelError() 并且它似乎对他们有用。有人说当 mvc 版本不同时会出现异常,但我已经检查过它们是相同的。

我可以缺少什么?

单元测试代码如下:

private Mock<IRegistrationService> registrationService;
    private RegistrationController registrationCtrl;

    public RegisteringANewUser()
    {
        registrationService = new Mock<IRegistrationService>();
        registrationCtrl = new RegistrationController(registrationService.Object);
        registrationCtrl.ModelState.Clear(); <- throws exception
    }

    [Fact]
    public void ShouldRegisterUser_WhenInputIsCorrect()
    {

        var registration = RegistrationHelper.CreateRegistrationVM("username", "password", "asfa@asf.com");

        registrationCtrl.Post(registration);

        registrationService.Verify(s => s.Register(registration), Times.Once);
    }
    [Fact]
    public void ShouldReturnBadRequest_WhenInputIsInvalid()
    {
        var registration = RegistrationHelper.CreateRegistrationVM("", "", "");
        registrationCtrl.ModelState.AddModelError("Error", "Error"); <- throws exception
        var result = registrationCtrl.Post(registration);

        Assert.Equal((int)HttpStatusCode.BadRequest, result.StatusCode);
    }

待测控制器功能:

public HttpStatusCodeResult Post(RegistrationVM registration)
    {
        if (!ModelState.IsValid) <- throws exception
        {
            return new HttpStatusCodeResult((int)HttpStatusCode.BadRequest);
        }

        _registrationService.Register(registration);
        return new HttpStatusCodeResult((int)HttpStatusCode.OK);
    }

project.json 用于单元测试库:

{
"version": "1.0.0-*",
"dependencies": {
    "Web": "1.0.0-*",
    "Moq": "4.2.1409.1722",
    "Xunit.KRunner": "1.0.0-rc1-10618",
    "Microsoft.AspNet.Mvc": "6.0.0-beta1"
},

"frameworks": {
    "aspnet50": {
        "dependencies": {
        }
    }

},
"commands": {
    "test": "Xunit.KRunner"
}
}

对于网站项目:

{
/* Click to learn more about project.json  http://go.microsoft.com/fwlink/?LinkID=517074 */
"webroot": "wwwroot",
"version": "1.0.0-*",
"dependencies": {
    "Microsoft.AspNet.Mvc": "6.0.0-beta1",
    //"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-beta1",
    "Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
    "Microsoft.AspNet.Security.Cookies": "1.0.0-beta1",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta1",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta1",
    "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta1",
    "Microsoft.Framework.CodeGenerators.Mvc": "1.0.0-beta1",
    "Microsoft.Framework.Logging": "1.0.0-beta1",
    "Microsoft.Framework.Logging.Console": "1.0.0-beta1",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta1",
    "mongocsharpdriver": "1.10.0.0-rc1"
},
"commands": {
    /* Change the port number when you are self hosting this application */
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000",
    "gen": "Microsoft.Framework.CodeGeneration"
},
"frameworks": {
    "aspnet50": { },
    "aspnetcore50": { } <- tried to remove this as I dont have it in my unit test lib without success
},
"exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
],
"packExclude": [
    "node_modules",
    "bower_components",
    "**.kproj",
    "**.user",
    "**.vspscc"
],
"scripts": {
    "postrestore": [ "npm install" ],
    "prepare": [ "grunt bower:install" ]
}
}

这确实是一个差距(直到 beta3)。被这个Issue

跟踪

在 Beta3 版本中(或者你可以在一天左右的时间内获得开发版本),我们将只初始化一个单元测试 ViewDataDictionary 这样你的单元测试将得到一个空的 ModelState.

这是来自 Controller.cs

的新代码片段
    [Activate]
    public ViewDataDictionary ViewData
    {
        get
        {
            if (_viewData == null)
            {
                // This should run only for the controller unit test scenarios
                _viewData =
                    new ViewDataDictionary(new EmptyModelMetadataProvider(),
                                            ActionContext?.ModelState ?? new ModelStateDictionary());
            }

            return _viewData;
        }
        set
        {
            if (value == null)
            {
                throw
                    new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(ViewData));
            }

            _viewData = value;
        }
    }

和(代码不变)

    public ModelStateDictionary ModelState
    {
        get
        {
            return ViewData?.ModelState;
        }
    }