如何用asp.net mvc模拟测试

时间:2012-07-24 13:15:20

标签: asp.net-mvc asp.net-mvc-3 unit-testing appharbor

我正在编写一个我已经部署到appharbor的应用程序。我现在无法让我的项目构建,因为我扩展了我的测试。我相信问题是我使用db初始化程序用测试种子数据填充数据库。这些测试通过我的本地盒子,但是一旦我在appharbor上部署了测试失败。我怀疑我需要模拟数据,但我不知道如何做到这一点。作为一个例子,这是我对我的一个动作方法的控制器测试。

控制器

    // GET: /Lead/Url
    // TODO: Add optional url parameters
    public ActionResult Url(string pfirstname, string plastname, string phone, int leadsource)
    {

        var lead = new Lead();
        //store 
        lead.parent_FirstName = pfirstname;
        lead.parent_LastName = plastname;
        lead.parent_Phone = phone;
        lead.LeadSourceID = leadsource;
        lead.AgentID = 1;

        if (ModelState.IsValid)
        {
            leadRepository.InsertLead(lead);
            leadRepository.Save();
            ViewBag.Message = "Success";
        }

        return View(lead);
    }

    //
    // POST: /Lead/URL       
    [HttpPost, ActionName("Url")]
    public ActionResult Url(Lead lead)
    {
        return View();
    }

单元测试

[TestMethod]
    public void LeadUrl()
    {
        //ARRANGE
        ILeadRepository leadrepository = new LeadRepository(new LeadManagerContext());
        Database.SetInitializer<LeadManagerContext>(new LeadManagerInitializer());
        LeadController controller = new LeadController(leadrepository);

        //ACT
        ViewResult result = controller.Url("Brad", "woods","465-456-4965",1) as ViewResult;
        var lead = (Lead)result.ViewData.Model;

        //ASSERT
       Assert.AreEqual("Success" ,result.ViewBag.Message);
        /*check for valid data */
       Assert.AreEqual("Brad", lead.parent_FirstName);

    }

有人可以解释下一步我需要做些什么来改进这样的代码并让它在app harbour上再次成功运行?

2 个答案:

答案 0 :(得分:1)

实际上,您尚未验证控制器与其依赖项(存储库)之间的交互。这是最重要的部分 - 控制器应该将您的Lead对象传递给存储库。然后调用Save(也考虑工作单元模式)。

另外,您应该单独测试控制器,只有这样您可以确定,控制器测试失败是控制器的问题,而不是LeadRepositoryLeadManagerInitializer

// Arrange
Lead expected = CreateBrad();    
var repository = new Mock<ILeadRepository>();
LeadController controller = new LeadController(repository.Object);    
// Act
ViewResult result = (ViewResult)controller.Url("Brad", "woods", "465-456", 1);
// Assert      
Lead actual = (Lead)result.ViewData.Model;
// All fields should be equal, not only name
Assert.That(actual, Is.EqualTo(expected));
Assert.AreEqual("Success", result.ViewBag.Message);
// You need to be sure, that expected lead object passed to repository
repository.Verify(r => r.InsertLead(expected));
repository.Verify(r => r.Save());

BTW我已将预期的Lead创建移到了单独的方法:

private Lead CreateBrad()
{
    Lead lead = new Lead();
    lead.parent_FirstName = "Brad";
    lead.parent_LastName = "woods";
    lead.parent_Phone = "465-456";
    lead.LeadSourceID = 1;
    lead.AgentID = 1;
    return lead;
}

此外,您应该覆盖Equals实例比较的Lead方法:

public class Lead
{
   // your current code here

   public override bool Equals(object obj)
   {
       Lead other = obj as Lead;
       if (other == null)
           return false;

       return other.parent_FirstName == parent_FirstName &&
              other.parent_LastName == parent_LastName &&
              // compare other properties here
              other.AgentID == AgentID;
   }

   // also override GetHashCode method
}

BTW为什么你没有将Lead对象传递给你的动作方法(通过POST消息)?

答案 1 :(得分:1)

您必须存根您的存储库。最简单的方法是使用模拟框架(我更喜欢Moq),并存根每个方法。

像这样(对于Moq):

var repository = new Mock<ILeadReporisory>();
repository.Setup(r => r.InsertLead(It.IsAny<Lead>()));
//raise, rinse, repeat

LeadController controller = new LeadController(repository.Object);