Overloading static imports

In a test class, Id would like to provide my own overloading with assertEquals

some special logic not relying on Object.equals

. Unfortunately this doesn't work because as soon as I declare my method assertEquals

locally Java no longer finds static imports from org.junit.Assert.*

.

Is there a way to get around this? That is, is there a way to provide additional overloading of a statically imported method? (A fairly obvious solution is to name the method differently, but this solution does not have the same aesthetic appeal.)

My test class file looks something like this:

package org.foo.bar;

import static org.junit.Assert.*;

import org.junit.Test;

public class BarTest {
    private static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }

    @Test
    public void testGetFoo() throws Exception {
        Bar a = new Bar();
        assertEquals(42, a.getFoo()); // Error *
    }

    @Test
    public void testCopyConstructor() throws Exception {
        Bar a = new Bar();
        // Fill a.
        Bar b = new Bar(a);
        assertEquals(a, b);
    }
}

      

Error *

: "Method assertEquals(Bar, Bar)

on type is BarTest

not valid for arguments (int, int)

."

+2


source to share


4 answers


There are two sections in this answer, one about compilation error and the other about using assertEquals ()

The problem is that there are two assertEquals () methods in two different namespaces: one is present in the org.junit.Assert namespace, the other in the org.foo.bar.BarTest namespace (the current namespace).

The error is reported by the compiler due to shadow copying rules declared in the Java Language specification . The static import Assert.assertEquals () is shadowed by the assertEquals () declared in the BarTest class.

The fix (always in the case of shadow ads) is to use FQNs (Fully Qualified Names). If you are going to use the assertEquals (...) of the JUnit Assert class use

org.junit.Assert.assertEquals(...)

      

and when you need to use your expression just use

assertEquals(...)

      



only in BarTest where it is shaded. In all other classes that only require Assert.assertEquals () or BarTest.asserEquals (), you can import Assert or BarTest (I don't think you would need to import BarTest elsewhere, but stated nonetheless this).

If there is no shadow, you can just import the class or static method and use it without the FQN.

More information about

Assert.assertEquals () internally uses the equals () method of the argument classes. The assertEquals () declaration in your test case violates the DRY principle, since the equals () method of the type must be implemented and used consistently - put two different implementations in the source code, and cause confusion in unit tests.

A better approach would be to implement equals () in Bar and then use Assert.assertEquals () in your test cases. If you already have one, you don't need BarTest.assertEquals (). The pseudocode for assertEquals () is somewhat similar to the following

  • If both arguments are zero, return true.
  • If the expected value is not null then call equals () while waiting for the actual to be passed as an argument. Return true if the object is equal.
  • If the objects are not equal, fire an AssertionError with a formatted message.
+3


source


One possible solution for your specific example of a call assertEquals(Bar, Bar)

in a unit test would be to extend the class with the method that the static method provides, like this:

class BarAssert extends Assert {
  public static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }
}

      



Then you can include import static BarAssert.assertEquals;

and use your own logic.

Apologies for not directly answering the question and focusing more on your example. As per my comment related to the question, I would recommend against this approach.

+3


source


The only way is to fully qualify one or the other.

import static org.junit.Assert.*;

import org.junit.Test;

public class BarTest {

    private static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }

    @Test
    public void testGetFoo() throws Exception {
        Bar a = new Bar();
        org.junit.Assert.assertEquals(42, a.getFoo());
    }
}

      

+1


source


this.assertEquals(a,b);

      

or

BarTest.assertEquals(a,b);

      

I'd go first, since even though it's a static method, you'll have to have an instance to use it (it's private) and this

won't succumb to the whims of future renames.

0


source







All Articles