Why doesn't JUnit provide assertNotEquals methods? - java

Does anybody know why JUnit 4 provides assertEquals(foo,bar) but not assertNotEqual(foo,bar) methods?
It provides assertNotSame (corresponding to assertSame) and assertFalse (corresponding to assertTrue), so it seems strange that they didn't bother including assertNotEqual.
By the way, I know that JUnit-addons provides the methods I'm looking for. I'm just asking out of curiosity.

I'd suggest you use the newer assertThat() style asserts, which can easily describe all kinds of negations and automatically build a description of what you expected and what you got if the assertion fails:
assertThat(objectUnderTest, is(not(someOtherObject)));
assertThat(objectUnderTest, not(someOtherObject));
assertThat(objectUnderTest, not(equalTo(someOtherObject)));
All three options are equivalent, choose the one you find most readable.
To use the simple names of the methods (and allow this tense syntax to work), you need these imports:
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

There is an assertNotEquals in JUnit 4.11: https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume
import static org.junit.Assert.assertNotEquals;

I wonder same. The API of Assert is not very symmetric; for testing whether objects are the same, it provides assertSame and assertNotSame.
Of course, it is not too long to write:
assertFalse(foo.equals(bar));
With such an assertion, the only informative part of the output is unfortunately the name of the test method, so descriptive message should be formed separately:
String msg = "Expected <" + foo + "> to be unequal to <" + bar +">";
assertFalse(msg, foo.equals(bar));
That is of course so tedious, that it is better to roll your own assertNotEqual. Luckily in future it will maybe be part of the JUnit: JUnit issue 22

I'd argue that the absence of assertNotEqual is indeed an asymmetry and makes JUnit a bit less learnable. Mind that this is a neat case when adding a method would diminish the complexity of the API, at least for me: Symmetry helps ruling the bigger space.
My guess is that the reason for the omission may be that there are too few people calling for the method. Yet, I remember a time when even assertFalse did not exist; hence, I have a positive expectation that the method might eventually be added, given that it is not a difficult one; even though I acknowledge that there are numerous workarounds, even elegant ones.

I'm coming to this party pretty late but I have found that the form:
static void assertTrue(java.lang.String message, boolean condition)
can be made to work for most 'not equals' cases.
int status = doSomething() ; // expected to return 123
assertTrue("doSomething() returned unexpected status", status != 123 ) ;

I am working on JUnit in java 8 environment, using jUnit4.12
for me: compiler was not able to find the method assertNotEquals, even when I used
import org.junit.Assert;
So I changed assertNotEquals("addb", string);toAssert.assertNotEquals("addb", string);
So if you are facing problem regarding assertNotEqual not recognized, then change it to Assert.assertNotEquals(,); it should solve your problem

The obvious reason that people wanted assertNotEquals() was to compare builtins without having to convert them to full blown objects first:
Verbose example:
....
assertThat(1, not(equalTo(Integer.valueOf(winningBidderId))));
....
vs.
assertNotEqual(1, winningBidderId);
Sadly since Eclipse doesn't include JUnit 4.11 by default you must be verbose.
Caveat I don't think the '1' needs to be wrapped in an Integer.valueOf() but since I'm newly returned from .NET don't count on my correctness.

It's better to use the Hamcrest for negative assertions rather than assertFalse as in the former the test report will show a diff for the assertion failure.
If you use assertFalse, you just get an assertion failure in the report. i.e. lost information on cause of the failure.

Usually I do this when I expect two objects to be equal:
assertTrue(obj1.equals(obj2));
and:
assertFalse(obj1.equals(obj2));
when they are expected to be unequal. I am aware that this not an answer to your question but it is the closest I can get. It could help others searching for what they can do in JUnit versions before JUnit 4.11.

I agree totally with the OP point of view. Assert.assertFalse(expected.equals(actual)) is not a natural way to express an inequality.
But I would argue that further than Assert.assertEquals(), Assert.assertNotEquals() works but is not user friendly to document what the test actually asserts and to understand/debug as the assertion fails.
So yes JUnit 4.11 and JUnit 5 provides Assert.assertNotEquals() (Assertions.assertNotEquals() in JUnit 5) but I really avoid using them.
As alternative, to assert the state of an object I general use a matcher API that digs into the object state easily, that document clearly the intention of the assertions and that is very user friendly to understand the cause of the assertion failure.
Here is an example.
Suppose I have an Animal class which I want to test the createWithNewNameAndAge() method, a method that creates a new Animal object by changing its name and its age but by keeping its favorite food.
Suppose I use Assert.assertNotEquals() to assert that the original and the new objects are different.
Here is the Animal class with a flawed implementation of createWithNewNameAndAge() :
public class Animal {
private String name;
private int age;
private String favoriteFood;
public Animal(String name, int age, String favoriteFood) {
this.name = name;
this.age = age;
this.favoriteFood = favoriteFood;
}
// Flawed implementation : use this.name and this.age to create the
// new Animal instead of using the name and age parameters
public Animal createWithNewNameAndAge(String name, int age) {
return new Animal(this.name, this.age, this.favoriteFood);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getFavoriteFood() {
return favoriteFood;
}
#Override
public String toString() {
return "Animal [name=" + name + ", age=" + age + ", favoriteFood=" + favoriteFood + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((favoriteFood == null) ? 0 : favoriteFood.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Animal)) return false;
Animal other = (Animal) obj;
return age == other.age && favoriteFood.equals(other.favoriteFood) &&
name.equals(other.name);
}
}
JUnit 4.11+ (or JUnit 5) both as test runner and assertion tool
#Test
void assertListNotEquals_JUnit_way() {
Animal scoubi = new Animal("scoubi", 10, "hay");
Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
Assert.assertNotEquals(scoubi, littleScoubi);
}
The test fails as expected but the cause provided to the developer is really not helpful. It just says that the values should be different and output the toString() result invoked on the actual Animal parameter :
java.lang.AssertionError: Values should be different. Actual: Animal
[name=scoubi, age=10, favoriteFood=hay]
at org.junit.Assert.fail(Assert.java:88)
Ok the objects are not equals. But where is the problem ?
Which field is not correctly valued in the tested method ? One ? Two ? All of them ?
To discover it you have to dig in the createWithNewNameAndAge() implementation/use a debugger while the testing API would be much more friendly if it would make for us the differential between which is expected and which is gotten.
JUnit 4.11 as test runner and a test Matcher API as assertion tool
Here the same scenario of test but that uses AssertJ (an excellent test matcher API) to make the assertion of the Animal state: :
import org.assertj.core.api.Assertions;
#Test
void assertListNotEquals_AssertJ() {
Animal scoubi = new Animal("scoubi", 10, "hay");
Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
Assertions.assertThat(littleScoubi)
.extracting(Animal::getName, Animal::getAge, Animal::getFavoriteFood)
.containsExactly("little scoubi", 1, "hay");
}
Of course the test still fails but this time the reason is clearly stated :
java.lang.AssertionError:
Expecting:
<["scoubi", 10, "hay"]>
to contain exactly (and in same order):
<["little scoubi", 1, "hay"]>
but some elements were not found:
<["little scoubi", 1]>
and others were not expected:
<["scoubi", 10]>
at junit5.MyTest.assertListNotEquals_AssertJ(MyTest.java:26)
We can read that for Animal::getName, Animal::getAge, Animal::getFavoriteFood values of the returned Animal, we expect to have these value :
"little scoubi", 1, "hay"
but we have had these values :
"scoubi", 10, "hay"
So we know where investigate : name and age are not correctly valued.
Additionally, the fact of specifying the hay value in the assertion of Animal::getFavoriteFood() allows also to more finely assert the returned Animal. We want that the objects be not the same for some properties but not necessarily for every properties.
So definitely, using a matcher API is much more clear and flexible.

Modulo API consistency, why JUnit didn't provide assertNotEquals() is the same reason why JUnit never provided methods like
assertStringMatchesTheRegex(regex, str) vs. assertStringDoesntMatchTheRegex(regex, str)
assertStringBeginsWith(prefix, str) vs. assertStringDoesntBeginWith(prefix, str)
i.e. there's no end to providing a specific assertion methods for the kinds of things you might want in your assertion logic!
Far better to provide composable test primitives like equalTo(...), is(...), not(...), regex(...) and let the programmer piece those together instead for more readability and sanity.

Related

Access Lambda Arguments with Groovy and Spock Argument Capture

I am trying to unit test a Java class with a method containing a lambda function. I am using Groovy and Spock for the test. For proprietary reasons I can't show the original code.
The Java method looks like this:
class ExampleClass {
AsyncHandler asynHandler;
Component componet;
Component getComponent() {
return component;
}
void exampleMethod(String input) {
byte[] data = input.getBytes();
getComponent().doCall(builder ->
builder
.setName(name)
.data(data)
.build()).whenCompleteAsync(asyncHandler);
}
}
Where component#doCall has the following signature:
CompletableFuture<Response> doCall(Consumer<Request> request) {
// do some stuff
}
The groovy test looks like this:
class Spec extends Specification {
def mockComponent = Mock(Component)
#Subject
def sut = new TestableExampleClass(mockComponent)
def 'a test'() {
when:
sut.exampleMethod('teststring')
then:
1 * componentMock.doCall(_ as Consumer<Request>) >> { args ->
assert args[0].args$2.asUtf8String() == 'teststring'
return new CompletableFuture()
}
}
class TestableExampleClass extends ExampleClass {
def component
TestableExampleClass(Component component) {
this.component = component;
}
#Override
getComponent() {
return component
}
}
}
The captured argument, args, shows up as follows in the debug window if I place a breakpoint on the assert line:
args = {Arrays$ArrayList#1234} size = 1
> 0 = {Component$lambda}
> args$1 = {TestableExampleClass}
> args$2 = {bytes[]}
There are two points confusing me:
When I try to cast the captured argument args[0] as either ExampleClass or TestableExampleClass it throws a GroovyCastException. I believe this is because it is expecting Component$Lambda, but I am not sure how to cast this.
Accessing the data property using args[0].args$2, doesn't seem like a clean way to do it. This is likely linked to the casting issue mentioned above. But is there a better way to do this, such as with args[0].data?
Even if direct answers can't be given, a pointer to some documentation or article would be helpful. My search results discussed Groovy closures and Java lambdas comparisons separately, but not about using lambdas in closures.
Why you should not do what you are trying
This invasive kind of testing is a nightmare! Sorry for my strong wording, but I want to make it clear that you should not over-specify tests like this, asserting on private final fields of lambda expressions. Why would it even be important what goes into the lambda? Simply verify the result. In order to do a verification like this, you
need to know internals of how lambdas are implemented in Java,
those implementation details have to stay unchanged across Java versions and
the implementations even have to be the same across JVM types like Oracle Hotspot, OpenJ9 etc.
Otherwise, your tests break quickly. And why would you care how a method internally computes its result? A method should be tested like a black box, only in rare cases should you use interaction testing,where it is absolutely crucial in order to make sure that certain interactions between objects occur in a certain way (e.g. in order to verify a publish-subscribe design pattern).
How you can do it anyway (dont!!!)
Having said all that, just assuming for a minute that it does actually make sense to test like that (which it really does not!), a hint: Instead of accessing the field args$2, you can also access the declared field with index 1. Accessing by name is also possible, of course. anyway, you have to reflect on the lambda's class, get the declared field(s) you are interested in, make them accessible (remember, they are private final) and then assert on their respective contents. You could also filter by field type in order to be less sensitive to their order (not shown here).
Besides, I do not understand why you create a TestableExampleClass instead of using the original.
In this example, I am using explicit types instead of just def in order to make it easier to understand what the code does:
then:
1 * mockComponent.doCall(_ as Consumer<Request>) >> { args ->
Consumer<Request> requestConsumer = args[0]
Field nameField = requestConsumer.class.declaredFields[1]
// Field nameField = requestConsumer.class.getDeclaredField('arg$2')
nameField.accessible = true
byte[] nameBytes = nameField.get(requestConsumer)
assert new String(nameBytes, Charset.forName("UTF-8")) == 'teststring'
return new CompletableFuture()
}
Or, in order to avoid the explicit assert in favour of a Spock-style condition:
def 'a test'() {
given:
String name
when:
sut.exampleMethod('teststring')
then:
1 * mockComponent.doCall(_ as Consumer<Request>) >> { args ->
Consumer<Request> requestConsumer = args[0]
Field nameField = requestConsumer.class.declaredFields[1]
// Field nameField = requestConsumer.class.getDeclaredField('arg$2')
nameField.accessible = true
byte[] nameBytes = nameField.get(requestConsumer)
name = new String(nameBytes, Charset.forName("UTF-8"))
return new CompletableFuture()
}
name == 'teststring'
}

How to test Comparator for JUnit test?

I need to test the compare() method and i am confused on how. Can I see how to do this?
public class MemberComparator implements Comparator<Member> {
private final String clientId;
public MemberComparator(String clientId) {
this.clientId = clientId;
}
#Override
public int compare(Member m1, Member m2) {
if (m1.getClientId().startsWith(clientId)) {
return m2.getClientId().startsWith(clientId) ? m1.getClientId().compareTo(m2.getClientId())
: -1;
} else {
return m2.getClientId().startsWith(clientId) ? 1
: m1.getClientId().compareTo(m2.getClientId());
}
}
}
So far, this is what i have created in my test. How can i get this to work? What should i do as this way isn't working, assuming i do not change the current approach to MemberComparator class.
class MemberComparatorTest {
//private MemberComparator caseID_test;
//private final MemberComparator memberComparator = new MemberComparator("jake");
#Test
void testEqual() {
Member m1 = new Member();
Member m2 = new Member();
int result = memberComparator.compare(m1,m2);
//assertTrue("expected to be equal", result == 0);
}
}
There are two questions you'd need to answer when writing a Comparator:
Does it meet the requirements of the Comparator interface?
Does it do what you need?
The first one is reasonably hard to write tests for; I'd argue it's better to write something using a "known good" pattern, in order to help you reason about its correctness from the code.
In the case of Comparator, the "known good" pattern is something that you see from the chaining methods:
// This boolean comparison may be the wrong way round, I never remember which way is which. If so, reverse it.
Comparator.comparing(m -> m.getClientId().startsWith(clientId))
.thenComparing(Member::getClientId)
You compare the first thing, and return if they're different; you compare the second thing, and return if they're different, etc.
You could use the code above if you're using Java 8+: this gives a totally fine Comparator. If you can't use this (for whatever reason), your compare method could be rewritten as:
int compareSw = Boolean.compare(m1.getClientId().startsWith(clientId), m2.getClientId().startsWith(clientId));
if (compareSw != 0) {
return compareSw;
}
return m1.getClientId().compareTo(m2.getClientId());
Because this follows the "known good" pattern, this can be seen to meet the requirements of the Comparator interface by inspection.
(Of course, you have to be careful about thinking "Looks Good To Me!", because you might miss something, e.g. using m1.getClientId() twice instead of both m1.getClientId() and m2.getClientId(). But that sort of defect would be caught by sufficient testing of the following).
Then it's just a matter of testing to make sure it does what you want: that is, if you take two Members, does this Comparator order them the way you want? That's an easy test to write, without getting bogged down in the details of the Comparator.
List<Member> members = List.of(m1, m2);
assertEquals(m1, Collections.min(members, comparator)); // For example.
assertEquals(m2, Collections.max(members, comparator)); // For example.
Some assertions might look like:
assertTrue(comparator.compare(m1, m1) == 0);
assertTrue(comparator.compare(m1, m2) > 0);
assertTrue(comparator.compare(m2, m1) < 0);

Better method for avoiding null in nested data with Java 7

I have to analyze a huge data stream which often includes incomplete data. Currently the code is littered with null checks at multiple levels, as there could be incomplete data at any level.
So for example I might have to retrieve:
Model.getDestination().getDevice().getName()
I tried to create a method to try and reduce the null checks to a single method whereby I enter:
IsValid(Model.getDestination(), Model.getDestination().getDevice(), Model.getDestination().getDevice().getName())
this method fails because it evaluates all parameters before it sends them, rather than checking each at a time like
Model.getDestination() != null && Model.getDestination().getDevice() != null && etc
but is there a way I could pass in Model.getDestination().getDevice().getName() and do the check at each level without having to evaluate it or split it up before I pass it?
What I really want it to do is if there is a null/nullexception it should quietly return "", and continue processing incoming data
I know there are ways to do this elegantly in Java 8, but I am stuck with Java 7
I struggled with a similar problem with deeply nested structures, and if I'd have had the opportunity to introduce additional structures just to navigate the underlying data, I think, I had done that.
This was C# which in the meantime has a save navigation/Elvis operator, for which we'll wait in vain with Java (proposed for Java 7 but discarded. Groovy has it btw.). Also looks like there are arguments against using Elvis, even if you have it). Also lambdas (and extension methods) didn't improve things really. Also every other approach has been discredited as ugly in other posts here.
Therefore I propose a secondary structure purely for navigation, each element with a getValue() method to access the original structure (also the shortcuts proposed by #Michael are straight forward to add this way). Allowing you null save navigation like this:
Model model = new Model(new Destination(null));
Destination destination = model.getDestination().getValue(); // destination is not null
Device device = model.getDestination().getDevice().getValue(); // device will be null, no NPE
String name = destination.getDevice().getName().getValue(); // name will be null, no NPE
NavDevice navDevice = model.getDestination().getDevice(); // returns an ever non-null NavDevice, not a Device
String name = navDevice.getValue().getName(); // cause an NPE by circumventing the navigation structure
With straight forward original structures
class Destination {
private final Device device;
public Destination(Device device) {
this.device = device;
}
public Device getDevice() {
return device;
}
}
class Device {
private final String name;
private Device(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And secondary structures for the purpose of save navigation.
Obviously this is debatable, since you always can access the original structure directly and run into a NPE. But in terms of readability perhaps I'd still take this, especially for large structures where a shrub of ifs or optionals really is an eyesore (which matters, if you have to tell, which business rules actually were implemented here).
A memory/speed argument could be countered by using only one navigation object per type and re-set their internals to approriate underlying objects as you navigate.
class Model {
private final Destination destination;
private Model(Destination destination) {
this.destination = destination;
}
public NavDestination getDestination() {
return new NavDestination(destination);
}
}
class NavDestination {
private final Destination value;
private NavDestination(Destination value) {
this.value = value;
}
public Destination getValue() {
return value;
}
public NavDevice getDevice() {
return new NavDevice(value == null ? null : value.getDevice());
}
}
class NavDevice {
private final Device value;
private NavDevice(Device value) {
this.value = value;
}
public Device getValue() {
return value;
}
public NavName getName() {
return new NavName(value == null ? null : value.getName());
}
}
class NavName {
private final String value;
private NavName(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Option 1 - if statement
You already provided it in your question. I think using am if statementlike the following is perfectly acceptable:
Model.getDestination() != null && Model.getDestination().getDevice() != null && etc
Option 2 - javax Validation and checking the result - before sending
You could make use of javax validation.
See: https://www.baeldung.com/javax-validation
You would annotate the fields that you want with #NotNull.
Then you could use programmatic validation.
You could check the validation result to see if there is a problem.
Example:
So in your class you would do:
#NotNull
Public String Destination;
And you could feed your object to the validater:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Model>> violations = validator.validate(Model);
for (ConstraintViolation<User> violation : violations) {
log.error(violation.getMessage());
}
Option 3 - fromNullable and Maps ( if you have Java 8)
I'm taking this one from https://softwareengineering.stackexchange.com/questions/255503/null-checking-whilst-navigating-object-hierarchies . This is very simular to your question.
import java.util.Optional;
Optional.fromNullable(model)
.map(Model::getDestination)
.map(Lounge::getDevice)
.ifPresent(letter -> .... do what you want ...);
Option 4 - Just using a try/catch
Everyone hates this one due to the slowness of exception.
So you want to simplify Model.getDestination().getDevice().getName(). First, I want to list a few things that should not be done: Don't use exceptions. Don't write an IsValid method, because it just doesn't work, because all functions (or methods) are strict in Java: that means that every time you call a function, all arguments are evaluated before they are passed to the function.
In Swift I would just write let name = Model.getDestination()?.getDevice()?.getName() ?? "". In Haskell it would be like name <- (destination >>= getDevice >>= getName) <|> Just "" (assuming the Maybe monad). And this has different semantics from this Java code:
if(Model.getDestination() && Model.getDestination().getDevice() && Model.getDestination().getDevice().getName() {
String name = Model.getDestination().getDevice().getName();
System.out.println("We got a name: "+name);
}
because this snippet calls getDestination() 4 times, getDevice() 3 times, getName() 2 times. This has more than just performance implications: 1) It introduces race conditions. 2) If any of the methods have side-effects, you don't want them to be called multiple times. 3) It makes everything harder to debug.
The only correct way of doing it is something like this:
Destination dest = Model.getDestination();
Device device = null;
String name = null;
if(dest != null) {
device = dest.getDevice();
if(device != null) {
name = device.getName();
}
}
if(name == null) {
name = "";
}
This code sets name to Model.getDestination().getDevice().getName(), or if any of these method calls return null, it sets name to "". I think correctness is more important than readability, especially for production applications (and even for example code IMHO). The above Swift or Haskell code is equivalent to that Java code.
If you have a production app, I guess that something like that is what you are already doing, because everything that is fundamentally different than that is error-prone.
Every better solution has to provide the same semantics and it MUST not call any of the methods (getDestination, getDevice, getName) more than once.
That said, I don't think you can simplify the code much with Java 7.
What you can do of course, is shorten the call chains: E.g. you could create a method getDeviceName() on Destination, if you need this functionality often. If this makes the code more readable depends on the concrete situation.
Forcing you to code on this low level also has advantages: you can do common subexpression elimination, and you'll see the advantages of it, because it will make the code shorter. E.g. if you have:
String name1 = Model.getDevice().getConnection().getContext().getName();
String name2 = Model.getDevice().getConnection().getContext().getLabel();
you can simplify them to
Context ctx = Model.getDevice().getConnection().getContext();
String name1 = ctx.getName();
String name2 = ctx.getLabel();
The second snippet has 3 lines, while the first snippet has only two lines. But if you unroll the two snippets to include null-checks, you will see that the second version is in fact much shorter. (I'm not doing it now because I'm lazy.)
Therefore (regarding Optional-chaining), Java 7 will make the code of the performance-aware coder look better, while many more high-level languages create incentives to make slow code. (Of course you can also do common subexpression elimination in higher level languages (and you probably should), but in my experience most developers are more reluctant to do it in high level languages. Whereas in Assembler, everything is optimized, because better performance often means you have to write less code and the code that you write is easier to understand.)
In a perfect word, we would all use languages that have built-in optional chaining, and we would all use it responsibly, without creating performance problems and race conditions.
You can use try-catch. Because there is no processing required in your case, like
try{
if(IsValid(Model.getDestination(), Model.getDestination().getDevice(), Model.getDestination().getDevice().getName())){
}catch(Exception e){
//do nothing
}
Alternatively you can improve your isValid method by passing only Model object
boolean isValid(Model model){
return (model != null && model.getDestination() != null && model.getDestination().getDevice() != null && model.getDestination().getDevice().getName() != null)
}

Why JUnit test methods need to be void?

I've read in lot of places that test methods should/must be void, but no one says what is the reason for this.
I found in MethodValidator the following check without comments/javadocs.
if (each.getReturnType() != Void.TYPE) {
errors.add(new Exception("Method " + each.getName()
+ " should be void"));
}
So why it should be void?
Ask you the reverse question : why JUnit test methods would need to be not void ?
No reason : because a test method is not designed to return a result that will be exploited by a client class.
The goal of an unit test is validating some assertions. A test runner invokes the test methods and and this is the runner that interprets any assertion failure or any exception thrown during the test execution to produce the test result.
We could wonder why tests don't return the assertion result.
But it would be a bad idea as it would be very cumbersome to write unit tests :
#Test
public AssertionResult foo(){
Bar actualBar = foo.doThat(...);
if (actualBar == null){
return AssertionResult.fail("actualBar == null");
}
}
Write something like that is really readable and straight :
#Test
public void foo(){
Bar actualBar = foo.doThat(...);
Assert.assertNotNull(actualBar);
}
We could also wonder why test methods cannot be invoked by other test methods such as :
#Test
public int foo(){
Bar actualBar = foo.doThat(...);
//...
return intValue;
}
#Test
public void fooWithComputedInt(){
Bar actualBar = foo.doThat(foo());
//...
}
But this also would be not a good idea as this would couple the tests execution while unit tests execution has to be isolated from others. And it also would make the tests be executed multiple times and unit tests have to be executed as fast as possible.
So really no value to make a test method return other thing than void.
This is purely a design choice. JUnit does not know about your code, so it could not do anything if your method would return something.
So either it should discard a return value, or require you to use "void" methods. The authors chose the latter option - you could argue that this slightly better because it's not confusing the reader.
Note that non-#Test methods are free to do whatever they want - they don't have this limitation.

How do I assert equality on two classes without an equals method?

Say I have a class with no equals() method, to which do not have the source. I want to assert equality on two instances of that class.
I can do multiple asserts:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
I don't like this solution because I don't get the full equality picture if an early assert fails.
I can manually compare on my own and track the result:
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
This gives me the full equality picture, but is clunky (and I haven't even accounted for possible null problems). A third option is to use Comparator, but compareTo() will not tell me which fields failed equality.
Is there a better practice to get what I want from the object, without subclassing and overridding equals (ugh)?
There is many correct answers here, but I would like to add my version too. This is based on Assertj.
import static org.assertj.core.api.Assertions.assertThat;
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.isEqualToComparingFieldByFieldRecursively(expectedObject);
}
}
UPDATE: In assertj v3.13.2 this method is deprecated as pointed out by Woodz in comment. Current recommendation is
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
Mockito offers a reflection-matcher:
For latest version of Mockito use:
Assert.assertTrue(new ReflectionEquals(expected, excludeFields).matches(actual));
For older versions use:
Assert.assertThat(actual, new ReflectionEquals(expected, excludeFields));
I generally implement this usecase using org.apache.commons.lang3.builder.EqualsBuilder
Assert.assertTrue(EqualsBuilder.reflectionEquals(expected,actual));
I know it's a bit old, but I hope it helps.
I run into the same problem that you, so, after investigation, I found few similar questions than this one, and, after finding the solution, I'm answering the same in those, since I thought it could to help others.
The most voted answer (not the one picked by the author) of this similar question, is the most suitable solution for you.
Basically, it consist on using the library called Unitils.
This is the use:
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);
Which will pass even if the class User doesn't implement equals(). You can see more examples and a really cool assert called assertLenientEquals in their tutorial.
If you're using hamcrest for your asserts (assertThat) and don't want to pull in additional test libs, then you can use SamePropertyValuesAs.samePropertyValuesAs to assert items that don't have an overridden equals method.
The upside is that you don't have to pull in yet another test framework and it'll give a useful error when the assert fails (expected: field=<value> but was field=<something else>) instead of expected: true but was false if you use something like EqualsBuilder.reflectionEquals().
The downside is that it is a shallow compare and there's no option for excluding fields (like there is in EqualsBuilder), so you'll have to work around nested objects (e.g. remove them and compare them independently).
Best Case:
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
assertThat(actual, is(samePropertyValuesAs(expected)));
Ugly Case:
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
SomeClass expected = buildExpected();
SomeClass actual = sut.doSomething();
assertThat(actual.getSubObject(), is(samePropertyValuesAs(expected.getSubObject())));
expected.setSubObject(null);
actual.setSubObject(null);
assertThat(actual, is(samePropertyValuesAs(expected)));
So, pick your poison. Additional framework (e.g. Unitils), unhelpful error (e.g. EqualsBuilder), or shallow compare (hamcrest).
You can use Apache commons lang ReflectionToStringBuilder
You can either specify the attributes you want to test one by one, or better, exclude those you don't want:
String s = new ReflectionToStringBuilder(o, ToStringStyle.SHORT_PREFIX_STYLE)
.setExcludeFieldNames(new String[] { "foo", "bar" }).toString()
You then compare the two strings as normal. For the point about reflection being slow, I assume this is only for testing, so shouldn't be so important.
Since this question is old, I will suggest another modern approach using JUnit 5.
I don't like this solution because I don't get the full equality picture if an early assert fails.
With JUnit 5, there is a method called Assertions.assertAll() which will allow you to group all assertions in your test together and it will execute each one and output any failed assertions at the end. This means that any assertions that fail first will not stop the execution of latter assertions.
assertAll("Test obj1 with obj2 equality",
() -> assertEquals(obj1.getFieldA(), obj2.getFieldA()),
() -> assertEquals(obj1.getFieldB(), obj2.getFieldB()),
() -> assertEquals(obj1.getFieldC(), obj2.getFieldC()));
The library Hamcrest 1.3 Utility Matchers has a special matcher that uses reflection instead of equals.
assertThat(obj1, reflectEquals(obj2));
Some of the reflection compare methods are shallow
Another option is to convert the object to a json and compare the strings.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public static String getJsonString(Object obj) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return bjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (JsonProcessingException e) {
LOGGER.error("Error parsing log entry", e);
return null;
}
}
...
assertEquals(getJsonString(MyexpectedObject), getJsonString(MyActualObject))
AssertJ assertions can be used to compare the values without #equals method properly overridden, e.g.:
import static org.assertj.core.api.Assertions.assertThat;
// ...
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
Using Shazamcrest, you can do:
assertThat(obj1, sameBeanAs(obj2));
Compare field-by-field:
assertNotNull("Object 1 is null", obj1);
assertNotNull("Object 2 is null", obj2);
assertEquals("Field A differs", obj1.getFieldA(), obj2.getFieldA());
assertEquals("Field B differs", obj1.getFieldB(), obj2.getFieldB());
...
assertEquals("Objects are not equal.", obj1, obj2);
You can use reflection to "automate" the full equality testing. you can implement the equality "tracking" code you wrote for a single field, then use reflection to run that test on all fields in the object.
In case you just need flat fields comparison you can use AssertJ
Assertions.assertThat(actual)).isEqualToComparingFieldByField(expected);
This is a generic compare method , that compares two objects of a same class for its values of it fields(keep in mind those are accessible by get method)
public static <T> void compare(T a, T b) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
AssertionError error = null;
Class A = a.getClass();
Class B = a.getClass();
for (Method mA : A.getDeclaredMethods()) {
if (mA.getName().startsWith("get")) {
Method mB = B.getMethod(mA.getName(),null );
try {
Assert.assertEquals("Not Matched = ",mA.invoke(a),mB.invoke(b));
}catch (AssertionError e){
if(error==null){
error = new AssertionError(e);
}
else {
error.addSuppressed(e);
}
}
}
}
if(error!=null){
throw error ;
}
}
I stumbled on a very similar case.
I wanted to compare on a test that an object had the same attribute values as another one, but methods like is(), refEq(), etc wouldn't work for reasons like my object having a null value in its id attribute.
So this was the solution I found (well, a coworker found):
import static org.apache.commons.lang.builder.CompareToBuilder.reflectionCompare;
assertThat(reflectionCompare(expectedObject, actualObject, new String[]{"fields","to","be","excluded"}), is(0));
If the value obtained from reflectionCompare is 0, it means they are equal. If it is -1 or 1, they differ on some attribute.
In common case with AssertJ you can create custom comparator strategy:
assertThat(frodo).usingComparator(raceComparator).isEqualTo(sam)
assertThat(fellowshipOfTheRing).usingElementComparator(raceComparator).contains(sauron);
Using a custom comparison strategy in assertions
AssertJ examples
I had the exact same conundrum when unit testing an Android app, and the easiest solution I came up with was simply to use Gson to convert my actual and expected value objects into json and compare them as strings.
String actual = new Gson().toJson( myObj.getValues() );
String expected = new Gson().toJson( new MyValues(true,1) );
assertEquals(expected, actual);
The advantages of this over manually comparing field-by-field is that you compare all your fields, so even if you later on add a new field to your class it will get automatically tested, as compared to if you were using a bunch of assertEquals() on all the fields, which would then need to be updated if you add more fields to your class.
jUnit also displays the strings for you so you can directly see where they differ. Not sure how reliable the field ordering by Gson is though, that could be a potential problem.
I tried all the answers and nothing really worked for me.
So I've created my own method that compares simple java objects without going deep into nested structures...
Method returns null if all fields match or string containing mismatch details.
Only properties that have a getter method are compared.
How to use
assertNull(TestUtils.diff(obj1,obj2,ignore_field1, ignore_field2));
Sample output if there is a mismatch
Output shows property names and respective values of compared objects
alert_id(1:2), city(Moscow:London)
Code (Java 8 and above):
public static String diff(Object x1, Object x2, String ... ignored) throws Exception{
final StringBuilder response = new StringBuilder();
for (Method m:Arrays.stream(x1.getClass().getMethods()).filter(m->m.getName().startsWith("get")
&& m.getParameterCount()==0).collect(toList())){
final String field = m.getName().substring(3).toLowerCase();
if (Arrays.stream(ignored).map(x->x.toLowerCase()).noneMatch(ignoredField->ignoredField.equals(field))){
Object v1 = m.invoke(x1);
Object v2 = m.invoke(x2);
if ( (v1!=null && !v1.equals(v2)) || (v2!=null && !v2.equals(v1))){
response.append(field).append("(").append(v1).append(":").append(v2).append(")").append(", ");
}
}
}
return response.length()==0?null:response.substring(0,response.length()-2);
}
For Unit testing I just serialize the object to a JSON string and compare it.
For example with Gson:
import com.google.gson.GsonBuilder
import junit.framework.TestCase.assertEquals
class AssertEqualContent {
companion object {
val gson = GsonBuilder().create()
fun assertEqualContent(message: String?, expected: Any?, actual: Any?) {
assertEquals(message, gson.toJson(expected), gson.toJson(actual))
}
}
}
As the expected and actual object is supposed to be of the same type the field order will be the same.
Pros:
You will get a nice string comparison highligting exactly where the difference is.
No extra libraries (provided that you have a JSON library already)
Cons:
Objects of different types might produce the same JSON (but if they do, you might consider why do you have different classes for the same data.... and how they could end up being compared in a testing method :-)
Can you put the comparision code you posted into some static utility method?
public static String findDifference(Type obj1, Type obj2) {
String difference = "";
if (obj1.getFieldA() == null && obj2.getFieldA() != null
|| !obj1.getFieldA().equals(obj2.getFieldA())) {
difference += "Difference at field A:" + "obj1 - "
+ obj1.getFieldA() + ", obj2 - " + obj2.getFieldA();
}
if (obj1.getFieldB() == null && obj2.getFieldB() != null
|| !obj1.getFieldB().equals(obj2.getFieldB())) {
difference += "Difference at field B:" + "obj1 - "
+ obj1.getFieldB() + ", obj2 - " + obj2.getFieldB();
// (...)
}
return difference;
}
Than you can use this method in JUnit like this:
assertEquals("Objects aren't equal", "", findDifferences(obj1, obj));
which isn't clunky and gives you full information about differences, if they exist (through not exactly in normal form of assertEqual but you get all the info so it should be good).
From your comments to other answers, I don't understand what you want.
Just for the sake of discussion, lets say that the the class did override the equals method.
So your UT will look something like:
SomeType expected = // bla
SomeType actual = // bli
Assert.assertEquals(expected, actual).
And you are done. Moreover, you can not get the "full equality picture" if the assertion fails.
From what I understand, you are saying that even if the type did override equals, you would not be interested in it, since you want to get the "full equality picture". So there is no point in extending and overriding equals either.
So you have to options: either compare property by property, using reflection or hard-coded checks, I would suggest the latter. Or: compare human readable representations of these objects.
For example, you can create a helper class that serializes the type you wish tocompare to an XML document and than compare the resulting XML! in this case, you can visually see what exactly is equal and what is not.
This approach will give you the opportunity to look at the full picture but it is also relatively cumbersome (and a little error prone at first).
You can override the equals method of the class like:
#Override
public int hashCode() {
int hash = 0;
hash += (app != null ? app.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
HubRule other = (HubRule) object;
if (this.app.equals(other.app)) {
boolean operatorHubList = false;
if (other.operator != null ? this.operator != null ? this.operator
.equals(other.operator) : false : true) {
operatorHubList = true;
}
if (operatorHubList) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Well, if you want to compare two object from a class you must implement in some way the equals and the hash code method

Categories