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:
MyProfit(NewYork new_york, Miami miami);
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.
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.
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?
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:
abstract sring FirstName();
abstract string LastName();
return FirstName() + " " + LastName();
class Person extends PersonBase
class FakePerson extends PersonBase
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.