How to test an array of objects with JUnit - java

Trying to check a method which adds a module object to an array works correctly. How do I write a JUnit test which tests to see if an object has indeed been added to the array?
Here is what I have so far:
#Test
public void testAddModule() {
Student chris = new Student("Chris", "1");
Module csc8001 = new Module("CSC8001", "Programming and data structures", 5, 5, 0, 7);
Module csc8002 = new Module("CSC8002", "Programming II", 5, 5, 0, 7);
chris.addModule(csc8001);
chris.addModule(csc8002);
Module [] expectedResult = {csc8001,csc8002};
ModuleRecord[] resultArray = Student.moduleRecords;
Assert.assertArrayEquals( expectedResult, resultArray );
}
The problem I have is the array is just storing references to the objects, how do I test to see if the array is storing the correct information?

You're on the right track: assertArrayEquals should work. The concept you're looking for is the difference between shallow equals ("==") and deep equals (".equals"), which is related to the difference between reference equality ("==") and object equality (".equals").
If two arrays have the same length, and contain the exact same primitive values and references, it's easy to say that they're equal: [0, 1] equals [0, 1] even if the arrays themselves are different objects, and the same happens for [csc8001, csc8002] and [csc8001, csc8002]. This is known as "shallow" equality, and it's very very fast to compute.
If you're actually looking to compare the objects using their equals methods, you need "deep" equality. This checks the proper number of entries, and checks that x[n].equals(y[n]) for all n. This may take longer, because Java can't just compare the references; it actually calls a method on the objects. This is only of value to you if you override equals, though; if your Module doesn't override equals it uses Object's built-in equals method, which acts the same way == does.
In any case, it's not very clear in the documentation, but Assert.assertArrayEquals calls Assert.internalArrayEquals, which basically does a deep comparison using .equals.
That leaves you with three options:
Keep using assertArrayEquals. That's what it's there for, and because equal references imply equal objects, it's the right thing to do.
Keep using assertArrayEquals but also write a Module.equals method to prove the data itself is identical. Remember, this is only an issue if you want to prove that two different instances behave as if they were equal based on their data, and you probably don't have to worry about that right now.
Break out what you're testing for, as Jason mentioned, which confirms that the data is correct without having you write an equals method:
assertEquals(2, resultArray.length);
Module addedModule = resultArray[1];
assertEquals("CSC8002", addedModule.code); /* ... */
If you ever do try overriding equals, be careful: You'll need to uphold some rules and you'll also need to override hashCode. Read more here.

The brute force method is to check that the array has the expected number of entries, then each object stored in the array has the expected attribute values.

Related

Why does Java need equals() if there is hashCode()?

If two objects return same hashCode, doesn't it mean that they are equal? Or we need equals to prevent collisions?
And can I implement equals by comparing hashCodes?
If two objects have the same hashCode then they are NOT necessarily equal. Otherwise you will have discovered the perfect hash function. But the opposite is true - if the objects are equal, then they must have the same hashCode.
hashCode and Equals are different information about objects
Consider the analogy to Persons where hashcode is the Birthday,
in that escenario, you and many other people have the same b-day (same hashcode), all you are not the same person however..
Why does Java need equals() if there is hashCode()?
Java needs equals() because it is the method through which object equality is tested by examining classes, fields, and other conditions the designer considers to be part of an equality test.
The purpose of hashCode() is to provide a hash value primarily for use by hash tables; though it can also be used for other purposes. The value returned is based on an object's fields and hash codes of its composite and/or aggregate objects. The method does not take into account the class or type of object.
The relationship between equals() and hashCode() is an implication.
Two objects that are equal implies that the have the same hash code.
Two objects having the same hash code does not imply that they are equal.
The latter does not hold for several reasons:
There is a chance that two distinct objects may return the same hash code. Keep in mind that a hash value folds information from a large amount of data into a smaller number.
Two objects from different classes with similar fields will most likely use the same type of hash function, and return equal hash values; yet, they are not the same.
hashCode() can be implementation-specific returning different values on different JVMs or JVM target installations.
Within the same JVM, hashCode() can be used as a cheap precursor for equality by testing for a known hash code first and only if the same testing actual equality; provided that the equality test is significantly more expensive than generating a hash code.
And can I implement equals by comparing hashCodes?
No. As mentioned, equal hash codes does not imply equal objects.
The hashCode method as stated in the Oracle Docs is a numeric representation of an object in Java. This hash code has limited possible values (represented by the values which can be stored in an int).
For a more complex class, there is a high possibility that you will find two different objects which have the same hash code value. Also, no one stops you from doing this inside any class.
class Test {
#Override
public int hashCode() {
return 0;
}
}
So, it is not recommended to implement the equals method by comparing hash codes. You should use them for comparison only if you can guarantee that each object has an unique hash code. In most cases, your only certainty is that if two objects are equal using o1.equals(o2) then o1.hashCode() == o2.hashCode().
In the equals method you can define a more complex logic for comparing two objects of the same class.
If two objects return same hashCode, doesn't it mean that they are equal?
No it doesn't mean that.
The javadocs for Object state this:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently
return the same integer, provided no information used in equals
comparisons on the object is modified. ...
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must
produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCodemethod on
each of the two objects must produce distinct integer results. ...
Note the highlighted statement. It plainly says "No" to your question.
There is another way to look at this.
The hashCode returns an int.
There are only 232 distinct values that an int can take.
If a.hashCode() == b.hashCode() implies a.equals(b), then there can be only 232 distinct (i.e. mutually unequal) objects at any given time in a running Java application.
That last point is plainly not true. Indeed, it is demonstrably not true if you have a large enough heap to hold 232 instances of java.lang.Object ... in a 64-bit JVM.
And a third way is to some well-known examples where two different two character strings have the same hashcode.
Given that your assumption is incorrect, the reasoning that follows from it is also incorrect.
Java does need an equals method.
You generally cannot implement equals using just hashCode.
You may be able to use hashCode to implement a faster equals method, but only if calling hashCode twice is faster than comparing two objects. It generally isn't.
hashCodes are equal -> Objects might be equal -> further comparision is required
hashCodes are different -> Object are not equal (if hashCode is implemented right)
That's how equals method are implemented. At first you check if hashCodes are equal. If yes, you need to check class fields to see if it represents the exact same object. If hashCodes are different, you can be sure that objects are not equal.
Sometimes (very often?) you don't!
These answers are not untrue. But they don't tell the whole story.
One example would be where you are creating a load of objects of class SomeClass, and each instance that is created is given a unique ID by incrementing a static variable, nInstanceCount, or some such, in the constructor:
iD = nInstanceCount++;
Your hash function could then be
int hashCode(){
return iD;
}
and your equals could then be
boolean equals( Object obj ){
if( ! ( obj instanceof SomeClass )){
return false;
}
return hashCode() == obj.hashCode();
}
... under such circumstances your idea that "equals is superfluous" is effectively true: if all classes behaved like this, Java 10 (or Java 23) might say, ah, let's just get rid of silly old equals, what's the point? (NB backwards compatibility would then go out the window).
There are two essential points:
you couldn't then create more than MAXINT instances of SomeClass. Or... you could ... if you set up a system for reassigning the IDs of previously destroyed instances. IDs are typically long rather than int ... but this wouldn't work because hashCode() returns int.
none of these objects could then be "equal" to another one, since equality = identity for this particular class, as you have defined it. Often this is desirable. Often it shuts off whole avenues of possibilities...
The necessary implication of your question is, perhaps, what's the use of these two methods which, in a rather annoying way, have to "cooperate"? Frelling, in his/her answer, alluded to the crucial point: hash codes are needed for sorting into "buckets" with classes like HashMap. It's well worth reading up on this: the amount of advanced maths that has gone into designing efficient "bucket" mechanisms for classes like HashMap is quite frightening. After reading up on it you may come to have (like me) a bit of understanding and reverence about how and why you should bother implementing hashCode() with a bit of thought!

ArrayList<int[]> containing a value

if i have an ArrayList<int[]> example and I want to check if {2,4} is in it how would I do this?
exaple.contains({2,4}); //doesn't work
and
exaple.contains(2,4); //doesn't work either
what is wrong with the code?
Arrays don't override the Object.equals() method (that ArrayList.contains() uses to compare objects). So an array is only equal to itself. You'll have to loop through the list and compare each element with your array using Arrays.equals().
What I suspect, though, is that you shouldn't have a List<int[]>, but a List<Coordinate>. The Coordinate class could then override equals() and hashCode(), and you would be able to use
example.contains(new Coordinate(2, 4))
You could also use a List<List<Integer>>, but if what I suspect is true (i.e. you're using arrays to hold two coordinates that should be in class), then go with the custom Coordinate class.
Even if you did it properly, ie:
int[] vals = {2, 4};
exaple.contains(vals);
You would not return true, because the contains method will use the equals method. Unless you have overridden the equals method, then this will always resolve to false, unless you pass in the exact same array.
You might want to take a look at this. And please post a bit of you're code.
i need to find a integer data in arraylist?
The contains() method checks, if ArrayList contains a specific object, it doesn't concern itself with the values inside an object. In other words, if you instantiate two {2,4} arrays, it will be two different objects and contains() method will diferentiate between them.
What you need to do is either override the contains() method to look on the content of arrays, instead of only the reference, or you can drop the contains() method completely and check it by hand.

Why assertEquals(new int[]{1}, new int[]{1}) results in failure?

I was testing my shuffling class and came across one issue I cannot understand. Why does the following assert statement:
assertEquals(new int[]{1}, new int[]{1});
results in an AssertionError? Naturally, the correct answer is "because they are not equal!", but could someone explain me why? And how to test a method, for which I would like the two such objects to be equal?
but could someone explain me why
Sure - arrays don't override equals, therefore they inherit the behaviour from Object, where any two distinct objects are non-equal.
It's even simpler than the version you showed if you use a 0-element array:
System.out.println(new int[0].equals(new int[0])); // false
That's why when checking for equality in non-test code you use Arrays.equals, and when checking for equality in test code you use a dedicated assertXyz method (where the exact method depends on the version of JUnit etc).
assertEquals calls the equals object in one of the objects to compare it with the other.
Arrays need to be compared using Arrays.equals() if you want a full comparison of the two arrays, otherwise unfortunately they just use the Object equals method.
See also: equals vs Arrays.equals in Java
Because you create 2 different objects and they point to different locations in the memory.
When comparing objects, you use the equals() method inherited from the class Object. Now, if you don't override the method in your class, you will have the default behaviour which is the comparison of objects address. In the code you create 2 arrays, but even though their content is the same, not the content is tested for being equal, but the objects reference by using the inherited equals() method from Object class.

comparing two XmlBeans Objects for equality

I've an XML Beans Interface called SynonymsRequest with:
public interface SynonymsRequest extends org.apache.xmlbeans.XmlObject {...}
I want to test two instances of SynonymsRequest for equality:
SynonymsRequest s1 = SynonymsRequest.Factory.newInstance();
s1.setQueryText("blub");
s1.setRequesterId(BigInteger.valueOf(1));
SynonymsRequest s2 = SynonymsRequest.Factory.newInstance();
s2.setQueryText("guck");
s2.setRequesterId(BigInteger.valueOf(1));
I've tried the following:
assertTrue(s1.equals(s2)); => assertion does not pass
assertEquals(0, s1.compareTo(s2)); => throws ClassCastException
assertEquals(0, s1.compareValue(s2)); => assertion does not pass (returns 2, not compareable)
assertTrue(s1.valueEquals(s2)); => always returns true, no matter if the two instances are equal
So what is the proper way of doing this?
If it doesn't impact the performance of your program, you could compare them like this:
assertTrue(s1.xmlText().equals(s2.xmlText()));
Otherwise, I guess you will have to write your own custom comparator.
As I understand, the comparison compares two simple values only. It cannot deduct your desired comparison algorithm.
Or I don't understand what exactly do you mean?
XmlBeans doesn't support a deep comparison so you'll have to write your own. There was a thread on the dev mailing list a while ago about a schema-aware comparison, but I'm not sure anything became of it:
http://www.mail-archive.com/dev#xmlbeans.apache.org/msg01960.html
Noticed this a while back - if the two objects have toString() methods generated when they were made, then you can to an .equals on the toString() methods of the objects. These can be compared with relativ ease, since they will check if the output xml is equivalent.

why we need to override equals and hashcode in java and why cannot we use Object class implementation

guys please let me know, in real world why we need to override equals and hashcode and cant we use Object's equals and hashcode.
Object's equals/hashcode implementation is fine - if you want "reference identity" as your equality. In other words, on object will always compare as equal to itself, but different to another object.
If, however, you want two distinct objects to be equal, you've got to override the method to say how they should be equal (and then override hashcode to be consistent with that).
The simplest example is probably String. Two different strings with the same characters are equal, and it's very useful for them to be equal:
String x = new String(new char[]{'a', 'b', 'c'});
String y = new String(new char[]{'a', 'b', 'c'});
System.out.println(x.equals(y)); // Prints true
Now compare that to FileInputStream - what would make two FileInputStreams equal? If they're reading the same file? What about the position within the file? What about two streams to different files with the same content? It doesn't really make a lot of sense to ask the question, IMO.
Now, how could the Object implementation know the difference between the desired behaviour of FileInputStream and String? It could potentially take note of annotations added to fields, properties and the type itself, possibly autogenerating appropriate bytecode which could then get JIT-compiled... but of course Java came out long before annotations were available. The current approach is very simple - but it does mean if you want value equality for distinct objects, you need to code it yourself.
One point to note is that equality is usually easier to think about for immutable types - it is odd if two objects are equal at one point in time and then non-equal later on. This can also seriously mess up hashtables - the hashcode should basically depend on the aspects of the object which are considered for equality, and the hashcode is recorded when a key is first added to a hashtable; if you then change the contents of the key, its hashcode would change, but the hashtable wouldn't know about it.
Because in real world if you use Object's implementation
new Integer( 1 ) is NOT equal to new Integer( 1 )

Categories

Resources