C# Unit Testing – Do Large Test Methods Indicate a Code Smell?

ccomplexitymockingunit testing

I have a particular method called TranslateValues() (Cyclomatic-Complexity of 5) which I would like to test.

The test requires a substantial number of mock objects which take up most of the method; The method being tested is fairly straightforward with this exceptional requirement. I am suspicious of this. For me, I might do something like this to alleviate the issue:

namespace TestArea
{
    [TestClass]
    public class PrimaryTests
    {
        //commonly used classes should go up here
        private CoreServiceClient client;
        public CoreServiceClient Client
        {
            get { return client; }
            set { client = value; }
        }

        [TestMethod]
        public void TestMethodForXYZ()
        {
            try
            {
              //use the Client, do some stuff, and assert
            }
            catch
            {
             //catch any problems, report them, and assert.fail
            }
        }
   }
}

But this will only take you so far in reducing the size and clutter of test methods, and so it begs the question: Are big test methods generally indicative of code smell? How do you gauge when your methods are becoming too big?

Best Answer

I say yes. You are testing too much.

I'm guilty of it myself but ideally you test one thing at a time (to be read as "one assert per test"). That's the Utopian view and so long as you're closer to that than the "one test for everything with a ton of asserts" side you're ok.

I think it really comes down to properly using the tool. NUnit, for example, has TestCaseAttributes so that you can have one test that runs through several cases, which you've basically described. Running them all through one test is less useful because it should stop at the first failure so you can only tell if you broke multiple cases by fixing the individual failures as you see them.

As for gauging when they are too big, it's pretty much as soon as I want to have a specific Assert run (and no others) but I can't because the test must run several other Asserts to remain valid.

In the end it really means following Single Responsibility when writing tests as well as code.