You should break up the class under question.
Each class should do some simple task. If you task is too complicated to test, then the task the class does is too big.
Ignoring the goofiness of this design:
class NewYork
{
decimal GetRevenue();
decimal GetExpenses();
decimal GetProfit();
}
class Miami
{
decimal GetRevenue();
decimal GetExpenses();
decimal GetProfit();
}
class MyProfit
{
MyProfit(NewYork new_york, Miami miami);
boolean bothProfitable();
}
UPDATE
The problem with stubbing methods in a class is that you are violating the encapsulation. Your test should be checking to see whether or not the external behaviour of the object matches the specifications. Whatever happens inside the object is none of its business.
The fact that FullName uses FirstName and LastName is an implementation detail. Nothing outside of the class should care that that is true. By mocking the public methods in order to test the object, you are making an assumption about that object is implemented.
At some point in the future, that assumption may cease to be correct. Perhaps all of the name logic will be relocated to a Name object which Person simply calls. Perhaps FullName will directly access member variables first_name and last_name rather then calling FirstName and LastName.
The second question is why you feel the need to do so. After all your person class could be tested something like:
Person person = new Person("John", "Doe");
Test.AssertEquals(person.FullName(), "John Doe");
You shouldn't feel the need stub anything for this example. If you do then you are stub-happy and well... stop it! There is no benefit to mocking the methods there because you've got control over what is in them anyways.
The only case where it would seem to make sense for the methods FullName uses to be mocked is if somehow FirstName() and LastName() were non-trivial operations. Maybe you are writing one of those random name generators, or FirstName and LastName query the database for answer, or something. But if that's what happening it suggest that object is doing something which doesn't belong in the Person class.
Putting it another way, mocking the methods is taking the object and breaking into two pieces. One piece is being mocked while the other piece is being tested. What you are doing is essentially an ad-hoc breaking up of the object. If that's the case, just break up the object already.
If your class is simple, you shouldn't feel the need to mock out pieces of it during a test. If your class is complex enough that you feel the need to mock, then you should break the class up into simpler pieces.
UPDATE AGAIN
The way I see it, an object has external and internal behavior. External behavior includes returns values calls into other objects etc. Obviously, anything in that category should be tested. (otherwise what would you test?) But internal behavior shouldn't really be tested.
Now the internal behavior is tested, because it is what results in the external behavior. But I don't write tests directly on the internal behavior, only indirectly through the external behavior.
If I want to test something, I figure it should be moved so that it becomes external behavior. That's why I think if you want to mock something, you should split the object so that the thing you want to mock is now in the external behavior of the objects in question.
But, what difference does it make? If FirstName() and LastName() are members of another object does it really change the issue of FullName()? If we decide that it is neccessary to mock FirstName and LastName does is actually help for them to be on another object?
I think if you use your mocking approach, then you create a seam in the object. You have functions like FirstName() and LastName() which directly communicate with an external data source. You also have FullName() which does not. But since they are all in the same class that is not apparent. Some pieces aren't supposed to directly access the data source and other are. Your code will be clearer if just break out those two groups.
EDIT
Let's take a step back and ask: why do we mock objects when we test?
- Make the tests run consistently (avoid accessing things which change from run to run)
- Avoid accessing expensive resources (don't hit third party services, etc.)
- Simplify the system under test
- Make it easier to test all possible scenarios (i.e. things like simulating failure, etc)
- Avoid depending on the details of other pieces of code so that changes in those other pieces of code won't break this test.
Now, I think reasons 1-4 don't apply to this scenario. Mocking the external source when testing fullname takes care of all of those reasons for mocking. The only piece not handled that is the simplicity, but it seems the object is simple enough that's not a concern.
I think your concern is reason number 5. The concern is that at some point in future changing the implementation of FirstName and LastName will break the test. In the future FirstName and LastName may get the names from a different location or source. But FullName will probably always be FirstName() + " " + LastName()
. That's why you want to test FullName by mocking FirstName and LastName.
What you have then, is some subset of the person object which is more likely to change then the others. The rest of the object uses this subset. That subset currently fetches its data using one source, but may fetch that data in a completely different way at a later date. But to me it sounds like that subset is a distinct object trying to get out.
It seems to me that if you mock the object's method you are splitting the object up. But you are doing so in a an ad-hoc manner. Your code does not make it clear that there are two distinct pieces inside your Person object. So simply split that object in your actual code, so that it is clear from reading your code what is going on. Pick the actual split of the object that makes sense and don't try to split the object up differently for each test.
I suspect you may object to splitting up your object, but why?
EDIT
I was wrong.
You should split objects rather then introducing ad-hoc splits by mocking individual methods. However, I was overly focused on the one method of splitting objects. However, OO provides multiple methods of splitting an object.
What I'd propose:
class PersonBase
{
abstract sring FirstName();
abstract string LastName();
string FullName()
{
return FirstName() + " " + LastName();
}
}
class Person extends PersonBase
{
string FirstName();
string LastName();
}
class FakePerson extends PersonBase
{
void setFirstName(string);
void setLastName(string);
string getFirstName();
string getLastName();
}
Maybe that is what you were doing all along. But I don't think this method will have the problems I saw with mocking methods because we've clearly delineated which side each method is on. And by using inheritance, we avoid the awkwardness that would arise if we used an additional wrapper object.
This does introduce some complexity, and for only a couple of utility functions I'd probably just test them by mocking the underlying 3rd party source. Sure, they are at increased danger of breaking but its not worth rearranging. If you've got a complex enough object that you need to split it, then I think something like this is a good idea.
Or if I should leave everything mocking and stubbing that tests the
designs and create new ones that tests the implementation.
A unit test never tests abstractions, or designs as you put it. It always tests one concrete implementation, that of the class under test.
In other words, if you have a test fixture for class A where you mock or stub out A's dependencies B and C, then you're not testing B and C's behavior or design. You're only testing A's behavior and that it is able to talk to B and C properly. In order to test concrete implementations of B and C, you have to create dedicated tests fixtures for both of them.
From a purely isolated unit test perspective, you neither need to substitute mocks for real implementations afterwards, nor to create integration test counterparts besides your unit tests (integration tests = tests involving several concrete implementations at the same time). Your isolated unit tests should stay as they are, with all the mocks and stubs. They stand on their own provided that you test all concrete implementations and their interactions with their dependencies.
As Erik points out, you could create integration tests, but keep in mind that they come at a cost, both in terms of processing time and maintenance time, and they shouldn't replace unit tests as your primary test harness IMO.
Best Answer
I see unit tests as routines that test pieces of code that are in a code base that you manage. Mocking and stubbing helps focus only on the flow and logic of your code, which is what you are testing in your unit tests.
Whether or not an outside service like a database (which is not inherently part of your code) actually works is not important for unit tests, but rather for integration tests.
Only if you have implemented routines to do simple database operations, should you tests whether those routines work like you expect them to, in unit tests. But then you would still stub out the database because you are not particularly interested in whether the database actually works, you are testing whether the logic in your code works.