Why are JUnit assert methods not generic in Java?

2019-02-24 07:56发布

问题:

I am using JUnit 4.12. The assert methods are not generic in nature. For instance, assertEquals method looks like:

static public void assertEquals(Object expected, Object actual) {..}

Why is it not like?

static public <T> void assertEquals(T expected, T actual) {..}

I felt need for generic method declaration for better compile time checking and IDE auto completion.

回答1:

Having a generic method like this:

<T> void assertEquals(T expected, T actual) { /* ... */ }

gives you no type safety to avoid comparing unlike types: you can pass in anything to this method, since T degenerates to its upper bound, Object:

assertEquals("string", 0);  // Compiles fine, even though they can't be equal.

Ideone demo

And nor can you use any methods on expected and actual that aren't found on Object. So, T is basically just Object.

As such, adding generics is just over-complicating the implementation.


Now, you could define a class like this:

class GenericAssert<T> {
  void assertEquals(T expected, T actual) { /* ... */ }
}

and you could use this like:

new GenericAssert<String>().assertEquals("string", 0);  // Compiler error.

because you've now placed a tighter upper bound on the acceptable parameters of assertEquals, at class level.

But this just feels a bit awkward.



回答2:

You want to look assertThat and the Hamcrest matchers; as assertThat actually works with generics:

assertThat(String reason, T actual, Matcher<? super T> matcher) 

So:

assertEquals("abc", 123); 

compiles, but fails; whereas

assertThat(123, is("abc")); 

won't even compile!

And I am not even mentioning that asserThat calls are much better to read; and give much better information when they fail. You can even use them to compare maps, sets, whatever.

Long story short: there is only one assert that anybody needs - assertThat that is!