Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question
1  
Is your "big method" doing more than one thing? That's typically a good marker. EDIT: Here's a nice high-level writeup on it (and a bunch of other code smells you might be interested in reading) sourcemaking.com/refactoring/long-method –  Chris Sinclair Jul 25 '12 at 22:06
    
It's hard to say, but the list that is being translated is a list of fairly robust objects. The translation is fairly straightforward - but mocking the objects the test requires, as jimmy_keen mentioned, is what is taking the most time/space. –  Ray Jul 25 '12 at 22:15
add comment

migrated from stackoverflow.com Jul 26 '12 at 23:10

This question came from our site for professional and enthusiast programmers.

4 Answers

up vote 2 down vote accepted

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.

share|improve this answer
    
Would you consider the case of Asserting multiple variables (which you could argue should be broken up into multiple tests) and instead sticking those variables into a class, overloading isEqual, and then doing a single assert on that object as skirting the single responsibility principle? –  Ray Jul 25 '12 at 22:31
    
@Ray: I would not. I would say that's how you're supposed to do it. –  Austin Salonen Jul 26 '12 at 0:13
add comment

I don't believe that a big test method is code smell by itself.

However, there are signs, for example when you

  • need to mock too much dependencies (too much is relative too)
  • need to setup too many things
  • need to know too many things about the actual implementation detail (when you do TDD it won't be a problem)
  • can't separate the testing of a method to well definied test cases (different test methods)

From my experience, one of the biggest sign that a method doing to much is when you can't really write a specific test case, just something like TestOfMyMethod(). That is probably not a test case, just a big mash of code covering the exact implementation of the actual method, which will break the next time you change anything.

share|improve this answer
add comment

No, not always. Big test methods are often results of testing/mocking frameworks and their workings (or, precisely - how you're supposed to use them).

For example, method might be perfectly fine and well-designed, but let's imagine it uses 2 or 3 dependencies - in order to test it, you'll probably have to stub/mock those dependencies. This adds extra lines of code to test method, which don't feel like attributing to tested method at all.

Having said that, too much dependencies might be good indicator (which, also will result in longer test method code due to extra setup work) and that's where I'd stay cautious, not the length itself.


Very trivial example of fairly common test, where test method will be "long", as compared to what it's actually testing (which probably is 1 line of code):

[Test]
public void GenerateReport_ThrowsInvalidOperationException_WhenTaskIsNotReady()
{
    var providerMock = new Mock<ITaskProvider>();
    providerMock.Setup(m => m.IsTaskReady).Returns(false);
    var sut = new ReportGenerator(providerMock);

    Assert.That(sut, Throws.InstanceOf<InvalidOperationException>());
}

Now, add bit more complex .Setup call, bit more complex assertion - this results in even more extended size of test method.

share|improve this answer
    
This is definitely what I am referring to here. I've updated the original question to clarify this; The translation itself isn't complex, but the mocking is quite elaborate. –  Ray Jul 25 '12 at 22:16
1  
@Ray: if you need substantial number of mocks, then yes - it might be indeed the problem (as in, your class is serving as a kind of manager/context/do-it-all service). Or your dependencies are too scattered and could be somehow merged (via facade pattern for example). I'd address this first, method length might not be the issue by itself - dependencies count is better suspect. –  jimmy_keen Jul 25 '12 at 22:23
add comment

Why your test could be long:

  • you are testing more than one thing
  • sut dependencies require lot of mocking (probably your case)
  • your sut requires lot of dependencies

If you are testing more than one thing

Write separate tests, for testing each thing. Each test will require less arranging, and less assertions. When some test will be broken, you will know what exactly is not working as expected.

If your mocks require lot of setup

First of all, you should verify why your sut asking it's dependency too much. Maybe you make decisions based on other object's state, thus violating Tell, Don't Ask principle. Consider moving that decisions logic to dependency.

// for this code you should setup mocks of person and address
if (person.Address != null) {
  Address address = person.Address;
  address.City = city;
}

vs

person.RelocateTo(city);

If you completely sure, that all logic in it's place, but your mock still requires some big setup, then consider moving mock creation to separate method. This also will allow to reuse that method in several tests.

Mock<Foo> fooMock = new Mock<Foo>();
fooMock.Setup(foo => foo.X).Returns("x");
fooMock.Setup(foo => foo.Y).Returns("y");
fooMock.Setup(foo => foo.Z).Returns("z");
Bar bar = new Bar(fooMock.Object);

vs

Foo foo = CreateFoo("x", "y", "z");
Bar bar = new Bar(foo);

If your sut requires lot of dependencies

If some of your dependencies always used together, than consider to introduce one object, which will hold them. Also check do you really need whole object to be passed. Maybe you just need one field from that object.

public void Foo(TimeProvider timeProvider)
{
   DateTime time = timeProvider.GetCurrentTime();
   ...
}

vs

public void Foo(DateTime currentTime)
{
   ...
}
share|improve this answer
    
Your answer was detailed and helpful. Austin's was just a bit more succinct. He also covers the Single Responsibility principle and gives a good example from NUnit, which I think gives context to the reader. –  Ray Jul 26 '12 at 21:25
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.