How should I structure my Unit tests for minimal Asserts? I always see comments about how a Unit Test should only be testing one piece of functionality. For the most part, I definitely agree with that assessment. However, I'm working on testing a method right now that has me pondering if being laxer on this ideal would be a better thing, so I'm curious to everyone's opinions.

The method that I'm testing is one that gathers Messages created between a user-defined date range, and groups them by Date, with totals of each type of Message per day. (Request, Offer, Dialog, and Referral).

So for a range of two days (for simplicity), I'll return an IEnumerable&lt;MessageDay&gt;, where MessageDay is defined as such:

public class MessageDay() {
    public DateTime Date { get; set; }
    public int Requests { get; set; }
    public int Offers { get; set; }
    public int Dialogs { get; set; }
    public int Referrals { get; set; }
    public int Total {
        get {
            return this.Requests + this.Offers + this.Dialogs + this.Referrals;
        }
    }
}


I have my Mock setup for my unit test with several of each type of Message, ranging from DateTime.MinValue, DateTime.Now, and DateTime.MaxValue.

Should I create a Unit Test with the same parameters going into the method I'm testing repeatedly? (i.e. first test will test a count of the days, second test will test the total Requests for day 1, etc for each type of Message, for each date)

I'm thinking that having so many tests (up to 13 per date range with 4 different date parameter possibilities) would be ridiculous, however I would like to know the standard, accepted way to do this.

EDIT
Here is my Mock data that I have set up:

[TestInitialize()]
public void TestInitialize() {
    var mock = new Mock&lt;IReportingRepository&gt;();
    var now = DateTime.Now;

    mock.Setup(m =&gt; m.Messages).Returns(new Message[] {
        new Request { CreatedOn = now },
        new Request { CreatedOn = DateTime.MinValue },
        new Request { CreatedOn = DateTime.MaxValue },
        new Offer { CreatedOn = DateTime.MinValue },
        new Offer { CreatedOn = DateTime.MinValue },
        new Offer { CreatedOn = DateTime.MaxValue },
        new Dialog { CreatedOn = now },
        new Dialog { CreatedOn = DateTime.MaxValue },
        new Referral { CreatedOn = now },
        new Referral { CreatedOn = DateTime.MinValue }
    }.AsQueryable());

    controller = new ReportingController(mock.Object);
}


This would be along the lines of my "fewest number of tests":

[TestMethod]
public void CanFindAllCounts() {
    var result = (MessageResponse)controller.GetMessageAnalytics(new MessageRequest()).Data;

    Assert.AreEqual(3, result.Days.Count());

    var day = result.Days.FirstOrDefault();
    Assert.AreEqual(4, day.Total);
    Assert.AreEqual(1, day.Requests);
    Assert.AreEqual(2, day.Offers);
    Assert.AreEqual(0, day.Dialogs);
    Assert.AreEqual(1, day.Referrals);

    day = result.Days.Where(d =&gt; d.Date.Date == DateTime.Now.Date).FirstOrDefault();
    Assert.AreEqual(3, day.Total);
    Assert.AreEqual(1, day.Requests);
    Assert.AreEqual(0, day.Offers);
    Assert.AreEqual(1, day.Dialogs);
    Assert.AreEqual(1, day.Referrals);

    day = result.Days.Last();
    Assert.AreEqual(3, day.Total);
    Assert.AreEqual(1, day.Requests);
    Assert.AreEqual(1, day.Offers);
    Assert.AreEqual(1, day.Dialogs);
    Assert.AreEqual(0, day.Referrals);
}


The other extreme would of course be a test for each of those Asserts. Being that I'm using Moq, it's not a huge deal and would run quickly, but I just feel that it's overkill.
In this case, what you're really trying to do is validate three MessageDays, as the return values of one method. As you are only testing one thing (the successful return of a method), you need not worry about testing too many things. I would, however, reduce the amount of asserts to three by implementing .Equals() on MessageDay.

While it may seem like overkill, .Equals() is a virtual method on System.Object, so you do already have an implementation of it available (just not the one you need, as it is currently a reference comparison).

I can't predict whether or not you'll need it again in the future, but I don't consider that a problem when implementing the method in question, because all objects have it. The effort is small, and the chances of using it somewhere other than just testing are high.

The downside is, of course, that your test will have to declare expected values, which may mean that it becomes no shorter, and the reduced number of asserts means your test is slightly less granular. For the second point, that's probably fine, because it also frees you to redesign the class without changing the test. The length could be reduced by  comparing with values saved in the test initialization.