title: How to unit test an abstract class method that depends on equals() with Mockito?
body: <p>I need to test an abstract class in Java, and I have a method which depends on <code>equals()</code> to provide a result.</p>
  
  <pre><code>public abstract class BaseClass&lt;T extends BaseClass&lt;T&gt;&gt; {
  
      public boolean isCanonical() {
          return toCanonical() == this;
      }
  
      public T toCanonical() {
          T asCanonical = asCanonical();
          if (equals(asCanonical)) {
              //noinspection unchecked
              return (T) this;
          }
          return asCanonical;
      }
  
      protected abstract T asCanonical();
  }
  </code></pre>
  
  <p>As you can see the <code>toCanonical()</code> method compare itself with <code>asCanonical</code> build calling the abstract method <code>asCanonical()</code>.</p>
  
  <p>To test this I need to create an empty implementation of my abstract class and make mockito calls real methods for the two implemented method and return my own classes for the asCanonical().</p>
  
  <pre><code>BaseClass aCanonicalClass;
  BaseClass aNonCanonicalClass;
  
  @Mock
  BaseClass sut;
  
  @Before
  public void setUp() {
      MockitoAnnotations.initMocks(this);
      // these are the methods under test, use the real ones
      Mockito.when(sut.isCanonical())
              .thenCallRealMethod();
      Mockito.when(sut.toCanonical())
              .thenCallRealMethod();
  }
  </code></pre>
  
  <p>Normally if this wasn't the <code>equals()</code> method I would just do this:</p>
  
  <pre><code>@Test
  public void test_isCanonical_bad() {
      // test true
      Mockito.when(sut.equals(aCanonicalClass))
              .thenReturn(true);
      Mockito.when(sut.equals(aNonCanonicalClass))
              .thenReturn(false);
      Mockito.when(sut.asCanonical())
              .thenReturn(aCanonicalClass);
      Assert.assertTrue(sut.isCanonical());
  
      // test false
      Mockito.when(sut.equals(aNonCanonicalClass))
              .thenReturn(true);
      Mockito.when(sut.equals(aCanonicalClass))
              .thenReturn(false);
      Mockito.when(sut.asCanonical())
              .thenReturn(aCanonicalClass);
      Assert.assertFalse(sut.isCanonical());
  }
  </code></pre>
  
  <p>Which give this error:</p>
  
  <blockquote>
  <pre><code>org.mockito.exceptions.misusing.MissingMethodInvocationException: 
  when() requires an argument which has to be 'a method call on a mock'.
  For example:
      when(mock.getArticles()).thenReturn(articles);
  
  Also, this error might show up because:
  1. you stub either of: final/private/equals()/hashCode() methods.
     Those methods *cannot* be stubbed/verified.
     Mocking methods declared on non-public parent classes is not supported.
  2. inside when() you don't call method on mock but on some other object.
  </code></pre>
  </blockquote>
  
  <p>One of Mockito limitations is that it doesn't allow to mock the <code>equals()</code> and <code>hashcode()</code> methods.</p>
  
  <p>As a workaround I just pass itself when I want to test the condition <code>equals() = true</code> and another random object when I want to test the condition <code>equals() = false</code>.</p>
  
  <pre><code>@Test
  public void test_isCanonical() {
      // test true
      Mockito.when(sut.asCanonical())
              .thenReturn(sut);
      Assert.assertTrue(sut.isCanonical());
  
      // test false
      Mockito.when(sut.asCanonical())
              .thenReturn(aCanonicalClass);
      Assert.assertFalse(sut.isCanonical());
  }
  </code></pre>
  
  <p>But this test pass even if I change the implementation to this:</p>
  
  <pre><code>    public T toCanonical() {
          T asCanonical = asCanonical();
          if (this == asCanonical) {
              //noinspection unchecked
              return (T) this;
          }
          return asCanonical;
      }
  </code></pre>
  
  <p>or even this:</p>
  
  <pre><code>    public T toCanonical() {
          return asCanonical();
      }
  </code></pre>
  
  <p>which is wrong! Comparison should be done with equals. Doing so by reference is not the same thing.</p>
  
  <p>Things gets impossible to test when I get to the <code>toCanonical()</code> method:</p>
  
  <pre><code>@Test
  public void test_toCanonical_bad() {
      // test canonical
      Mockito.when(sut.equals(aCanonicalClass))
              .thenReturn(true);
      Mockito.when(sut.equals(aNonCanonicalClass))
              .thenReturn(false);
      Mockito.when(sut.asCanonical())
              .thenReturn(aCanonicalClass);
      Assert.assertSame(sut, sut.toCanonical());
  
      // test non-canonical
      Mockito.when(sut.equals(aNonCanonicalClass))
              .thenReturn(true);
      Mockito.when(sut.equals(aCanonicalClass))
              .thenReturn(false);
      Mockito.when(sut.asCanonical())
              .thenReturn(aCanonicalClass);
      Assert.assertNotEquals(sut, sut.toCanonical());
      Assert.assertSame(aCanonicalClass, sut.toCanonical());
  }
  </code></pre>
  
  <p>This of course doesn't work, and doesn't really makes sense to apply the same workaround because I would just test that the return value of the function is the one of <code>asCanonical()</code>:</p>
  
  <pre><code>@Test
  public void test_toCanonical() {
      // test canonical
      Mockito.when(sut.asCanonical())
              .thenReturn(sut);
      Assert.assertSame(sut, sut.toCanonical());
  
      // test non-canonical
      Mockito.when(sut.asCanonical())
              .thenReturn(aCanonicalClass);
      Assert.assertNotEquals(sut, sut.toCanonical());
      Assert.assertSame(aCanonicalClass, sut.toCanonical());
  }
  </code></pre>
  
  <p>Both test are pointless because of the fact I can't mock the result of <code>equals()</code>.</p>
  
  <p>Is there a way to test at least <code>equals()</code> is being called with the object I gave it? (spy it)</p>
  
  <p>Is there any other way to test this?</p>
  
  <blockquote>
    <p><strong>EDIT</strong>: this is a semplification of the actual code I'm working with.</p>
    
    <p>I modified the example code to at least show the <code>toCanonical()</code> and <code>asCanonical()</code> methods are supposed to return instances of the same class (and not just any class)</p>
    
    <p>I want to test the base class here. Only the concrete implementation know how to build an actual canonical class (<code>asCanonical()</code>) or check if this class is equal to a canonical class (<code>equals()</code>). And please note that <code>toCanonical()</code> return ITSELF if it is equals to the canonical version of itself. Again <code>equals != same</code>.</p>
    
    <p>The actual implementations are immutable classes. And since they are many and this code is the same for everyone i put it in a base class.</p>
  </blockquote>