Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent stubbing of equals method

I would like to test my class' equals() method but Mockito seems to be calling the stub version every time. My test is as follows;

PluginResourceAdapter adapter = mock (PluginResourceAdapter.class);
PluginResourceAdapter other = mock (PluginResourceAdapter.class);

when(adapter.getNumberOfEndpointActivation()).thenReturn(1);
when(other.getNumberOfEndpointActivation()).thenReturn(0);

boolean result = adapter.equals(other);
assertFalse(result);

I know I cannot stub the equals method which means Mockito should be calling my real implementation but its not.

I have also tried this:

when (adapter.equals(any()).thenCallRealMethod()

but I get the same result.

like image 744
SJunejo Avatar asked Nov 04 '13 22:11

SJunejo


People also ask

What is lenient () in Mockito?

lenient() to enable the lenient stubbing on the add method of our mock list. Lenient stubs bypass “strict stubbing” validation rules. For example, when stubbing is declared as lenient, it won't be checked for potential stubbing problems, such as the unnecessary stubbing described earlier.

How do you use mock method in parameters?

Mockito mock() method All five methods perform the same function of mocking the objects. Following are the mock() methods with different parameters: mock() method with Class: It is used to create mock objects of a concrete class or an interface. It takes a class or an interface name as a parameter.

What is stubbing in Mockito?

A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.

What is stubbing in Java?

A stub is a controllable replacement for an existing dependency (or collaborator) in the system. By using a stub, you can test your code without dealing with the dependency directly. A mock object is a fake object in the system that decides whether the unit test has passed or failed.

Is it possible to stub the equals() method?

final/private/equals ()/hashCode () methods. Those methods cannot be stubbed/verified. so you will have to create real test object (not a mock) and then verify the equals () by comparing it with a real expected object.

What happens if equals () method is not overridden?

If this equals () method is not overridden, then by default equals (Object obj) method of the closest parent class which has overridden this method is used. In this sample, we have used String objects for comparison and the String class has its own overridden implementation of the equals () method.

Why does the equals () method of the string class return false?

Since the equals () method of the Object class returns true only if the references of the two objects are equal, this program returns false. The equals () method of the String class is not same as the equals () method of the Object class.

What is the use of method equals in Java?

The java.lang.reflect.Method.equals (Object obj) method of Method class compares this Method Object against the specified object as parameter to equal (object obj) method. This method returns true if Method object is same as passed object.


1 Answers

Even beyond Mockito's limitations, it doesn't make much sense for a mocked object to use a real equals method, if for no other reason than that equals methods almost always use fields, and mocked objects never run any of their constructors or field initializers.

Also, be aware of what you're testing: In a test of Foo, ideally you should never mock Foo, even to set up a Foo to compare against. Otherwise, it's easy to inadvertently test that Mockito works, rather than testing your own component's logic.

You have a few workarounds:

  • As Garrett Hall mentioned, create real objects. This may require factoring out the "data objects" from the services that use them, and mocking the services while using real data objects. This is probably a good idea overall.

  • Create a manual mock or fake by subclassing PluginResourceAdapter or implementing the relevant interface outside of Mockito. This frees you to define all methods as needed, including equals and hashCode.

  • Create an equivalentTo method, which isn't the same as equals (and thus isn't as useful for Map or Set objects, for instance) but that has mockable semantics you can define on your own.

    This would also let you test equivalentTo freely with a mock, and simply have equals delegate to that presumably-well-tested implementation.

  • Extract an object that tests equality, and mock that. You could also use Guava's Equivalence there, or a Comparator where you test a.compareTo(b) == 0.

    class YourClass {
      class AdapterEquivalence {
        boolean adaptersAreEqual(
            PluginResourceAdapter a, PluginResourceAdapter b) {
          return a.equals(b);
        }
      }
    
      /** Visible for testing. Replace in tests. */
      AdapterEquivalence adapterEquivalence = new AdapterEquivalence();
    }
    

Note that one other potential workaround—spying on existing instances—will also redefine equals and hashCode and won't help you here.

like image 161
Jeff Bowman Avatar answered Oct 14 '22 20:10

Jeff Bowman