C# 模拟非虚拟发布模型属性和方法

C# 模拟非虚拟发布模型属性和方法,c#,asp.net-mvc,unit-testing,moq,C#,Asp.net Mvc,Unit Testing,Moq,我将person模型类定义为: public class PersonModel { public bool SelectionSubmitted = false; public bool ShowValidationSummary = false; public string Name; public string Get() { //actual implementation return some val

我将person模型类定义为:

public class PersonModel
{
    public bool SelectionSubmitted = false;

    public bool ShowValidationSummary = false;

    public string Name;

    public string Get()
    {            
        //actual implementation return some value from the db
        return string.Empty;
    }
}
控制器的实现如下所示:

class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index(PersonModel model)
    {
        if (model.SelectionSubmitted && !ValidateSelections(model))
        {
            model.ShowValidationSummary = true;
        }

        return View("Index", model.Get());
    }

    private bool ValidateSelections(PersonModel model)
    {
        if(model.Name == "")
        {
            ModelState.AddModelError("EmptyPersonName", "Person name cannot be null");
        }
        return ModelState.IsValid;
    }       
}
测试类别和方法定义为:

[TestClass]
public class ChildWithoutPlacementControllerTest
{
    private readonly Mock<PersonModel> _mockPersonModel;

    public ChildWithoutPlacementControllerTest()
    {
        _mockPersonModel = new Mock<PersonModel>();
    }

    [TestMethod]
    public void GivenPerson_WhenSearchingForFutureBirthDate_ThenValidationMessageShouldBeShown()
    {
        //Arrange
        HomeController controller = new HomeController();
        _mockPersonModel.Setup(x => x.Get()).Returns(It.IsAny<string>());
        _mockPersonModel.SetupGet(x => x.Name).Returns(string.Empty);
        _mockPersonModel.SetupGet(x => x.SelectionSubmitted).Returns(true);

        //Act
        controller.Index(_mockPersonModel.Object);

        //Assert
        var isShowSummarySetToTrue = _mockPersonModel.Object.ShowValidationSummary;
        Assert.IsTrue(isShowSummarySetToTrue);
    }
}
[TestClass]
公共班级无职儿童控制员测试
{
私有只读Mock\u mockPersonModel;
无职业介绍的公共儿童控制员测试()
{
_mockPersonModel=新建Mock();
}
[测试方法]
当申请未来出生日期时,应显示验证消息()
{
//安排
HomeController=新的HomeController();
_mockPersonModel.Setup(x=>x.Get()).Returns(It.IsAny());
_SetupGet(x=>x.Name).Returns(string.Empty);
_mockPersonModel.SetupGet(x=>x.SelectionSubmitted)。返回(true);
//表演
controller.Index(_mockPersonModel.Object);
//断言
变量isShowSummarySetToTrue=\u mockPersonModel.Object.ShowValidationSummary;
Assert.IsTrue(isShowSummarySetToTrue);
}
}
我想要实现的是将
SelectionSubmitted
Name
属性分别模拟为
true
string.Empty
以及
Setup
类的
Get
方法,并检查测试返回对象是否已将
ShowValidationSummary
设置为
true

但是,我发现我无法设置非虚拟财产名称

我是否做错了什么,或者是否有任何方法可以在不更改实现代码的情况下做到这一点

我做错什么了吗

这似乎是一个错误

有没有办法在不改变实现代码的情况下实现它

在这种情况下,确实不需要最低起订量。您可以使用继承来创建一个假模型,以便在测试中使用。伪模型将覆盖与数据库紧密耦合的方法。(稍后将详细介绍)

然后可以重构测试以使用假模型,并按照预期完成测试

[TestMethod]
public void GivenPerson_WhenSearchingForFutureBirthDate_ThenValidationMessageShouldBeShown() {
    //Arrange
    var fakePersonModel = new FakePerson() {
        Name = string.Empty,
        SelectionSubmitted = true
    };
    var controller = new HomeController();

    //Act
    controller.Index(fakePersonModel);

    //Assert
    var isShowSummarySetToTrue = fakePersonModel.ShowValidationSummary;
    Assert.IsTrue(isShowSummarySetToTrue);
}
除此之外,如果实际的
Get
实现如您所述,那么您的模型似乎做了很多工作

实际实现从数据库返回一些值

考虑将该功能重构为服务(单一责任原则/关注点分离)

并尽可能保持模型的精益。还考虑将这些公共字段重构为公共属性。

public class PersonModel {
    public bool SelectionSubmitted { get; set; }

    public bool ShowValidationSummary { get; set; }

    public string Name { get; set; }

}
控制器将依赖于服务抽象

class HomeController : Controller {
    private IPersonModelService service;

    public HomeController(IPersonModelService service) {
        this.service = service;
    }

    [HttpGet]
    public ActionResult Index(PersonModel model) {
        if (model.SelectionSubmitted && !ValidateSelections(model)) {
            model.ShowValidationSummary = true;
        }

        return View("Index", service.Get(model));
    }

    private bool ValidateSelections(PersonModel model) {
        if (model.Name == "") {
            ModelState.AddModelError("EmptyPersonName", "Person name cannot be null");
        }
        return ModelState.IsValid;
    }
}
现在,测试可以单独进行到完成

[TestMethod]
public void GivenPerson_WhenSearchingForFutureBirthDate_ThenValidationMessageShouldBeShown() {
    //Arrange
    var model = new PersonModel() {
        Name = string.Empty,
        SelectionSubmitted = true
    };

    var serviceMock = new Mock<IPersonModelService>();
    serviceMock.Setup(_ => _.Get(It.IsAny<PersonModel>())).Returns(string.Empty);
    var controller = new HomeController(serviceMock.Object);

    //Act
    controller.Index(model);

    //Assert
    var isShowSummarySetToTrue = model.ShowValidationSummary;
    Assert.IsTrue(isShowSummarySetToTrue);
}
[TestMethod]
当申请未来出生日期时,应显示验证消息(){
//安排
var model=newpersonmodel(){
Name=string.Empty,
SelectionSubmitted=true
};
var serviceMock=new Mock();
serviceMock.Setup(=>wk.Get(It.IsAny())).Returns(string.Empty);
var控制器=新的HomeController(serviceMock.Object);
//表演
控制器索引(模型);
//断言
var isShowSummarySetToTrue=model.ShowValidationSummary;
Assert.IsTrue(isShowSummarySetToTrue);
}

可能与@nkosi重复我猜你发布了答案,但现在找不到。这确实帮助了我,这种方法对我很有效。非常感谢!!。我发现了它的一个问题,并且正在检查这个问题。你应该考虑重构你的代码以使它更易于测试。是的,我正在研究如何使它更易于测试。
class HomeController : Controller {
    private IPersonModelService service;

    public HomeController(IPersonModelService service) {
        this.service = service;
    }

    [HttpGet]
    public ActionResult Index(PersonModel model) {
        if (model.SelectionSubmitted && !ValidateSelections(model)) {
            model.ShowValidationSummary = true;
        }

        return View("Index", service.Get(model));
    }

    private bool ValidateSelections(PersonModel model) {
        if (model.Name == "") {
            ModelState.AddModelError("EmptyPersonName", "Person name cannot be null");
        }
        return ModelState.IsValid;
    }
}
[TestMethod]
public void GivenPerson_WhenSearchingForFutureBirthDate_ThenValidationMessageShouldBeShown() {
    //Arrange
    var model = new PersonModel() {
        Name = string.Empty,
        SelectionSubmitted = true
    };

    var serviceMock = new Mock<IPersonModelService>();
    serviceMock.Setup(_ => _.Get(It.IsAny<PersonModel>())).Returns(string.Empty);
    var controller = new HomeController(serviceMock.Object);

    //Act
    controller.Index(model);

    //Assert
    var isShowSummarySetToTrue = model.ShowValidationSummary;
    Assert.IsTrue(isShowSummarySetToTrue);
}