10

Why is there so much hating going on about 'partial mocking' and the code that requires it?

Here's an (theoretical) example implementation:

public ComplexResult1 operationA(Stimulus a) {
    {
        ...
        result = ...;
    }
    auditTheChange(a);
}
public ComplexResult2 operationB(Stimulus b) {
    {
        ...
        result = ...;
    }
    auditTheChange(b);
    return result;
}
void auditTheChange(Stimulus stim) {
    // do a bunch of stuff to record the change
    // and interact with another outside service
}

Now, in my understanding this is well refactored code.

If I want to UNIT test operationA and operationB, and ensure that auditing happens in each scenario, but without having to test the specifics of the audit code, I would use partial mocking.

What am I not seeing/understanding that causes so many projects (EasyMock, Mockito, etc.) to recommend refactoring?

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
Nelz
  • 111
  • 5
  • Who is the one making blanket statements against all use of partial mocks? – Kirk Woll Sep 27 '10 at 19:16
  • That's a rather unwarranted use of the word "hating" – skaffman Sep 27 '10 at 19:18
  • 1
    @kirk, from EasyMock documentation: "In this case, the first thing to do is to consider a refactoring since most of the time this problem caused by a bad design. If it's not the case or if you can't do otherwise because of some development constraints, here's the solution." – Nelz Sep 27 '10 at 20:32

3 Answers3

4

If auditing is truly an internal function of the class then the code should be tested as part of the unit test. Why does your class handle both complex operations and auditing? Could the auditing be moved to a separate class?

If so, introduce the auditing as a collaborator with this class and mock it out. If not, unit test it.

You can use partial mocks, but in this case I think it is an indication the class is doing too much.

emulcahy
  • 1,055
  • 3
  • 18
  • 28
  • 1
    A valid use case could be if all public methods call some sort of cleanUp() at the end of them. In this case, you can write a unit test for cleanUp(), itself. Then, when testing all public methods, use a partial mock to simply verify that cleanUp() was called avoiding the need to verify the details of what cleanUp() did in every public method. – Chris Morris Apr 25 '14 at 12:55
1

The key point is "what is the unit being tested".

A lot of developers think OO. In OO, "object" is the unit of software so that object is also the unit that is tested in the unit test. In your example, auditTheChange() is a private method in an object. A unit test should focus on the behavior of public method only. Mock a private method means the unit test case dealing with some implementation detail of the unit which is considered as a "code smell".

Some developers think the unit of software is "method". In your example, you do think in this way. Because operationA and operationB is too complicated so that you create auditTheChange so that the complexity of unit operationA and operationB can be reduced. If you think in this way, partial mocking is not a "code smell" because the method is a unit being tested and mocking a private method also means "focus on behavior, not implementation details".

There is no absolute right or wrong here. It really depends on the nature of your project or team. I worked for a company developing an enterprise info system using Spring. In Spring, almost all business logic is implemented in xxxService objects. When a method is too complicated, we just move some logic to a private method as you did in your example. If we always move that logic to a new class, there will be a lot of classes and objects will be created and that will make the programs difficult to maintain. So, we just moved the logic to private methods and used partial mocks. Actually, a lot of people needed partial mocks. You can check this Mockito document. At the beginning, mockito thinks partial mock is a code smell. After a long discussion and debate, they also support partial mocks now.

philu
  • 795
  • 1
  • 8
  • 17
1

If auditTheChange is a private function, then you just don't write a test which verifies its invocation. You don't want your unit test be tightly coupled to an implementation.

And just in general: Don't unit test private methods.

  • @NatFar The question was if PartialMock is a code smell. It is one when you are not able to test something you intend on testing. But in case you are sure your design of classes is fine and you are using partial mock then most likely its a sign you are trying to test something you don't need to. – Oleg Piruyan Mar 02 '20 at 08:28