1

I am writing an app that I have been deploying to appharbor. I am having trouble getting my project to build now because I have expanded my tests. I believe the issue is that I am using a db initializer to populate the database with test seed data. These tests pass on my local box but once I deploy the tests fail on appharbor. I suspect I need to mock data but I am not sure how to do this. As an example, here is a controller test that I have for one of my action methods.

Controller

    // 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();
    }

Unit Test

[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);

    }

Could someone please explain what I need to do next in order to improve code like this and get it to run again on app harbor successfully?

B Woods
  • 580
  • 3
  • 7
  • 21

2 Answers2

1

Actually you haven't verified interactions between controller and it's dependencies (repository). And this is the most important part - controller should pass your Lead object to repository. And then call Save (consider also to Unit Of Work pattern).

Also you should test controller in isolation, only this way you could be sure, that failing controller's test is an issue of controller, not of LeadRepository or LeadManagerInitializer.

// 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 I'd moved expected Lead creation to separate method:

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;
}

Also you should override Equals method for Lead instances comparison:

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 Why you don't pass Lead object to your action method (via POST message)?

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • Ok this makes sense a little bit. What package do I need to run this? Is it Moq? – B Woods Jul 24 '12 at 13:51
  • Yes, Moq. It is very simple and powerful. – Sergey Berezovskiy Jul 24 '12 at 13:55
  • I was getting an error in the POST. I am going to try and move that code into the POST today. Im surprised but it works in the GET still. – B Woods Jul 24 '12 at 14:33
  • are you sure about this line of code? Assert.That(actual, Is.EqualTo(expected)); – B Woods Jul 24 '12 at 14:46
  • This is for NUnit test framework. For MSTest you can use `Assert.AreEqual(actual, expected)`. Don't forget to override `Equals` method on your `Lead` class! – Sergey Berezovskiy Jul 24 '12 at 14:49
  • See my update. Also consider to use Pascal Casing without underscores for property names. – Sergey Berezovskiy Jul 24 '12 at 14:58
  • Great thanks for the tips everything passes now. Why would I need to override GetHashCode? – B Woods Jul 24 '12 at 15:04
  • To avoid warning message in visual studio, that it was not overridden. And to avoid surprises when you will use `Lead` with dictionary, hashtable, etc. Those classes use GetHashCode to compare items. See http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c – Sergey Berezovskiy Jul 24 '12 at 15:15
1

You have to stub your repository. The easiest way to do that is to use mocking framework (I prefer Moq), and stub each method.

Something like this (for Moq):

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

LeadController controller = new LeadController(repository.Object);
Sergei Rogovtcev
  • 5,804
  • 2
  • 22
  • 35
  • what do you mean by stub your repository? – B Woods Jul 24 '12 at 13:43
  • Replace it by an implementation that does exactly what you need for testing. If you're have not heard of it, then, most probably, you're doing something very wrong with you unit testing. I would highly recommend reading [Osherove's The Art of Unit Testing](http://www.manning.com/osherove/). – Sergei Rogovtcev Jul 24 '12 at 13:43
  • sounds like I am on the right track. I have the book open right now on my desk trying to figure all this out. – B Woods Jul 24 '12 at 13:49