I'm trying to get the hang of Java. Unit testing is pretty important to me and so recently I've started to use JUnit. It was tough to begin with but I'm getting the hang of it. All of my tests have worked up to this point, with the exception of comparing two objects of the same class (I haven't tried testing a function that creates an object of a different class). Basically, when I have a method within a class that creates a new instance of the class, and I try to test the method, I get a weird error.
"expected:runnersLog.MTLog#433c675d but was runnersLog.MTLog#3f91beef"
I have tried researching this problem, but haven't found anything of much help. Here's the link to my classes on github. The method I am trying to test is the mt() method, and the test class is ILogTest.
This is not the only case where I am having this problem. With any class that has a method that returns a new object of the same class, I am getting this exact same 3f91beef error (even when the object is more complicated - with arguments)
assertEquals will use Object#equals for each object being compared. Looks like your class ILogTest doesn't override equals method, so calling Object#equals will just compare the references by itself, and since they're different object references, the result will be false.
You have two options:
Override public boolean equals(Object o) in ILogTest.
Use assertEquals on the relevant fields that implement equals method e.g. String, Integer, Long, etc. This one requires more code but is useful when you cannot modify the class(es) being asserted.
You need to overrride equals, the equals method in the superclass Object checks for references if both references point to the same object equals is true if not false, so you need to write down an equals method that will check your objects content and check if the values are the same, it is also recommended that you override your hashCode method too.
An example could be:
Custom a= new Custom("");
Custom b= a;
//b would be equal a. because they reference the same object.
Custom c= new Custom("");
//c would not be equal to a, although the value is the same.
to learn more you could check:
Why do I need to override the equals and hashCode methods in Java?
If you are using a modern IDE for development (like Eclipse, IntelliJ etc), they can generate these methods for you. Check that out for two reasons: 1) to save time 2) To prevent possible bugs.
In eclipse IDE, you can do so by selecting source -> generate hashCode() and equals().
One more thing, when you implement of of these two, you have to implement the other one as well.
Related
I want to assert the object which is returned from the method that I am testing in Junit using Assertions.AssertEquals but its giving test case failure even though two objects are same.
Expected :Customer{Id=1, Name='ABC', Price=350, Type='ABC'} Actual :Customer{Id=1, Name='ABC', Price=350, Type='ABC'}
This is the unit test case
#Test
public void getCustomerById_Test(){
Dishes test1 = repo.getById(1);
assertEquals(ExpectedObject,ActualObject);
}
JUnit method assertEquals simply uses equals method of your class to compare the objects - you have to implement the method properly for the assertion to work correctly. You can read more about implementing equals in multiple online sources, for example here.
If you don't want to implement equals in the verified class, you can also use assertEquals to compare object fields you're interested in, like so:
assertEquals(7, actual.getSomeValue());
assertEquals("abcd", actual.getOtherValue());
If you added the AssertJ library, you could use it's usingRecursiveComparison method - for details refer to the documentation.
This question already has answers here:
java why should equals method input parameter be Object
(6 answers)
Overloading in Java and multiple dispatch
(6 answers)
Closed 4 years ago.
I was making some tests with the java equals method and I figured out that if my parameter is not of the generic type Object the test won’t pass, even if the two objects I create are of that type. Let’s say I want to check if an object is an animal, what I tried to do is writing down:
public boolean equals(Animal other) {
*some code*
}
And then I create a test for that method to compare the animals. But if I do that the test will fail, on the other side, if I write down:
public boolean equals(Object other) {
*some code*
}
and then test it, the test will pass. I understand that’s useless declaring the object of the desired type and try to test it but I don’t get why it doesn’t work in a good weather test case.
It is simple, Object class equals method signature is this
public boolean equals(Object obj)
But if you write equals method with Animal parameter then it will not be the Overridden equals method from object class. and when you try to compare objects by using .equals() Object class equals will be invoked
For this reason and to make it clear it is always recommended to use #Override annotation
The equals method is part of the base Object class in Java and the only way to make benefit of it is to override it. To override it you need to stick to the same signature which will tell any libraries using equals to invoke your method instead of the base one.
Your above code is doing an overloading which is a totally different method to the Java compiler.
I have implemented a method that returns a Connection object.
Now I want to unit test that method and when I make the typical
assertEquals(expectedConnection, actualConnection);
it fails with the error code:
java.lang.AssertionError: expected
[org.sqlite.SQLiteConnection#1a968a59] but found
[org.sqlite.SQLiteConnection#4667ae56]
I hoped the test passed as, even when the objects are not the same (that's why I haven't used assertSame), they have the same characteristics (have been built in the same way, with the same class atributes)... Is there any way to test Connection objects?
NB: I have the same issue with the unit test of a method that returns a statement
Thanks for your help!!
assertEquals(expected, actual) uses equals method of the object. And SQLiteConnection inherits it's equals() method from Object class.
Since default equals implementation compares the references to check whether two references, are referencing the same object. This compares is bound to fail. Since in your case, both the references are referencing to different object, hence difference hash code.
You can use ArgumentCaptor instead to capture the values in the actual object and compare them. Here is an example
I dont think it is a good idea to create a new connection and compare with actual connection. You could assert user , password, and connection string rather than asserting the actual connection.
I this case it is clear that you are comparing the reference. You can assert only on classes which overrides equals(Object o) from Object class to be precise SQLiteConnection does not override equals method from Object.
I have the following code,
Object testA = new Object();
Object testB = testA;
System.out.println("A:"+testA.hashCode())
System.out.println("B:"+testB.hashCode())
Per the above, I get the same hashcode for the two objects. I understand that testB is assigned testA and so it could have the same hashcode, however there should be a way to uniquely identify the difference in both these objects right?
Please let me know if there is something obvious that am missing!
however there should be a way to uniquely identify the difference in both these objects right?
There is no difference, since there are no two objects. There is just one object referred by two variables.
In theory, two different objects may have the same hashCode. You can tell them apart by using equals or by using ==. If you don't override equals, it behaves as == by default.
The hashCode function has to be compatible with the equals method in the sense that hashCode has to return the same value for 2 objects that are equal. In this case, they are not only "equal" (according to the equals method), but even the same object (which implies that they are equal).
Besides, independently of what the specification demands, it would impossible for the 2 calls to hashCode to return different values because both variables are actually referencing the same object. There is no way to distinguish testA and testB (apart from the variable name, of course).
You create a new object testA but then assign testB to testA, which assigns the same memory space for both of the objects. This is why its returning the same HashCode.
I've a huge project with many classes. I've a very specific class; let's name it SuperFoo. I need to find all calls to the method equals() with argument of type Superfoo. Hope it's clear.
So, one more time... in thousands of java files (or bytecode?) I'd like to find all calls to the method java.lang.Object.equals(Object arg) but the argument to this call must be of type SuperFoo. For example:
public void doItWith(SuperFoo foo) {
if (otherFoo.equals(foo)){
// do something
}
...
}
I checked out Browse-by-query, analyzing bytecode and just Java Search in Eclipse and in my opinion none of this works.
A programmatic approach would be to use Aspect Oriented Programming (i.e. AspectJ). You would define a pointcut to capture the method call of interest
pointcut equals(Superfoo o) = call(boolean *.equals(Object)) && args(o);
and then use advice to select each occurrence and query the joinpoint object to get the static information i.e. where it appears in your code.
before(Superfoo o) : equals(o) {
System.out.println("An occurence at "+thisJoinPoint.getSourceLocation());
}
So, you are trying to find out the references of
public boolean equals(Object o)
overridden in SuperFoo. If you have access to the source code, this could be done in eclipse. If you go for Call Hierarchy, eclipse returns back all the occurrence of Object's equals() method. So, you need try the following:
Open SuperFoor. Select the equals method. Right Click. References --> Project. In the resulting search window, on the extreme right, click on the triangle. Select "references to override". That's it. The results returned initially will be filtered and it will mostly contain references of equals overridden in SuperFoo.
Hope this helps.