views:

305

answers:

3

When unit testing a codebase, what are the tell-tale signs that I need to utilise mock objects?

Would this be as simple as seeing a lot of calls to other objects in the codebase?

Also, how would I unit test methods which don't return values? So if I a method is returning void but prints to a file, do I just check the file's contents?

Mocking is for external dependencies, so that's literally everything, no? File system, db, network, etc...

+1  A: 

If anything, I probably over use mocks.

Whenever a class makes a call to another, generally I mock that call out, and I verify that the call was made with the correct parameters. Else where, I'll have a unit test that checks the concrete code of the mocked out object behaves correctly.

Example:

[Test]
public void FooMoo_callsBarBaz_whenXisGreaterThan5()
{
    int TEST_DATA = 6;
    var bar = new Mock<Bar>();
    bar.Setup(x => x.Baz(It.Is<int>(i == TEST_DATA)))
       .Verifiable();

    var foo = new Foo(bar.Object);

    foo.moo(TEST_DATA);

    bar.Verify();
}

...
[Test]
public void BarBaz_doesSomething_whenCalled()
{
   // another test
}

The thing for me is, if I try to test lots of classes as one big glob, then there's usually tonnes of setup code. Not only is this quite confusing to read as you try to get your head around all the dependencies, it's very brittle when changes need to be made.

I much prefer small succinct tests. Easier to write, easier to maintain, easier to understand the intent of the test.

Kirschstein
You end up tieing test to internal implementaion details with mocks which mean they tend to break more often. With state based testing you only care about an output. Mocks are generally more messy to set up, but they certainly have their place in unit testing.
Finglas
A: 

Unit tests are only for one piece of code that works autonomously within itself. This means that it doesn't depend on other objects to do its work. You should use mocks if you are doing Test-Driven programming or Test-First programming. You would create a mock (or stub as I like to call it) of the function you will be creating and set certain conditions for the test to pass. Originally the function returns false and the test fails, which is expected ... then you write the code to do the real work until it passes.

But what I think you are referring to is integration testing, not unit testing. In that case, you should use mocks if you are waiting for other programmers to finish their work and you currently don't have access to the functions or objects they are creating. If you know the interface, which hopefully you do otherwise mocking is pointless and a waste of time, then you can create a dumbed-down version of what you are hoping to get in the future.

In short, mocks are best utilized when you are waiting for others and need something there in order to finish your work.

You should try to always return a value if possible. Sometimes you run into problems where you are already returning something, but in C and C++ you can have output parameters and then use the return value for error checking.

Brian T Hannan
-1 - This is based on a misunderstanding of mocks and stubs. While you certainly stub out functionality when doing TDD, that isn't what mock objects are for. You don't mock the object under test, you mock its dependencies.
TrueWill
Yeah, I guess there is a difference between stubs and mocks. I think you misunderstood what I said. In the first paragraph I was describing what unit tests were and how you might use an object you created that simulates a real-object that you currently don't have access to or don't care to have access to. In the second paragraph I started describing that mocks are for integration testing ... but I was wrong. Integration testing is done after unit testing and is done with real objects, not mocks. Either way, mocks are best utilized when you want to do unit testing before you integrate.
Brian T Hannan
A: 

Mocks/stubs/fakes/test doubles/etc. are fine in unit tests, and permit testing the class/system under test in isolation. Integration tests might not use any mocks; they actually hit the database or other external dependency.

You use a mock or a stub when you have to. Generally this is because the class you're trying to test has a dependency on an interface. For TDD you want to program to interfaces, not implementations, and use dependency injection (generally speaking).

A very simple case:

public class ClassToTest
{
   public ClassToTest(IDependency dependency)
   {
      _dependency = dependency;
   }

   public bool MethodToTest()
   {
      return _dependency.DoSomething();
   }
}

IDependency is an interface, possibly one with expensive calls (database access, web service calls, etc.). A test method might contain code similar to:

// Arrange

var mock = new Mock<IDependency>();

mock.Setup(x => x.DoSomething()).Returns(true);

var systemUnderTest = new ClassToTest(mock.Object);

// Act

bool result = systemUnderTest.MethodToTest();

// Assert

Assert.That(result, Is.True);

Note that I'm doing state testing (as @Finglas suggested), and I'm only asserting against the system under test (the instance of the class I'm testing). I might check property values (state) or the return value of a method, as this case shows.

I recommend reading The Art of Unit Testing, especially if you're using .NET.

TrueWill
Care to explain why the downvote?
TrueWill