我是这个 C# 世界的初学者。
有这个模型类:
public class Fund
{
[Required]
public int id { get; set; }
[Required]
public string name { get; set; }
[Required]
public string nickname { get; set; }
}
尽管 [Required]
注释覆盖了所有属性,但实例如下:
Fund f = new Fund();
f.name = "test name";
f.nickname = "test ninckname";
总是通过这样的测试:
if (ModelState.IsValid)
{
// do stuff
}
我应该如何设置模型以使这样的实例不会通过 ModelState.IsValid
测试?
其他情况如:
Fund f1 = new Fund();
f1.id = 3;
f1.nickname = "test ninckname";
和
Fund f2 = new Fund();
f2.id = 3;
f2.name = "test name";
也通过了测试。
编辑:
ModelState.IsValid
在 Controller 内部,我正在实际测试 Controller 。
编辑 2:
这是 Controller 的方法签名:
[HttpPatch]
public ActionResult EditFund(Fund fund)
编辑 3: 这就是我的整个测试方法:
[TestMethod]
public void TestEditInvalidFund()
{
// Arrange
FundController controller = new FundController();
controller.ControllerContext = TestModelHelper.AdminControllerContext();
var _fund = new Mock<IFund>();
_fund.SetupGet(f => f.id).Returns(1);
//_fund.SetupGet(f => f.name).Returns("Fund name");
_fund.SetupGet(f => f.nickname).Returns("Fund nickname");
_fund.Setup(f => f.Edit()).Callback(() => {}).Verifiable();
// Act
var result = (JsonResult)controller.EditFund(_fund.Object);
// Assert
SimpleMessage resultMessage = m_serializer.Deserialize<SimpleMessage>(m_serializer.Serialize(result.Data));
Assert.IsNotNull(resultMessage.status, "JSON record does not contain 'status' required property.");
Assert.IsTrue(resultMessage.status.Equals("fail"), "status must be 'fail'");
}
这就是整个 Controller 的方法:
[HttpPatch]
public ActionResult EditFund(IFund _fund)
{
try
{
if (ModelState.IsValid)
{
//_fund.Edit();
}
else
{
string error_messages = "";
foreach (var e in ModelState.Select(x => x.Value.Errors).Where(y => y.Count > 0).ToList())
{
error_messages += e[0].ErrorMessage + "\n";
}
throw new Exception(error_messages);
}
return MessageHelper(@Resources.Global.success, @Resources.Funds.success_editing_fund, "success");
}
catch (Exception err)
{
return ErrorHelper(@Resources.Global.error, @Resources.Funds.error_editing_fund, err.Message);
}
}
最佳答案
你不能单元测试ModelState.IsValid
.好吧,你可以,但是你需要额外的代码来完成它,而且它并不是很理想。
这是我在 github 上的代码: WithModelStateIsInvalid<TController>()
这是它所在的 NuGet 包:https://www.nuget.org/packages/TestBase-Mvc/
下面是我如何使用它:
UnitUnderTest
.WithModelStateIsInValid()
.Action(model)
.ShouldBeViewResult()
.ShouldBeAnInvalidModel();
——————————————————————————————————————————
您无法对其进行单元测试的原因是模型验证发生在模型绑定(bind)步骤之前您的 Controller 操作被调用。
所以要模拟模型验证失败,最简单的方法是使controller.ModelState
失效在调用操作之前,在单元测试代码中“手动”。这是扩展方法的作用,但实际上它只是一行:
controller.ModelState.AddModelError("FieldName", @"error message")
(更复杂的扩展方法可能会让您指定哪个模型键无效。PR 总是受欢迎的)。
关于C# MVC 模型在对 Controller 操作进行单元测试时始终有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41882876/