当 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;
}
}
我正在尝试对我的控制器进行单元测试,其中包含对 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;
}
}