Compare all properties in two objects of different classes in unit test - java

I have some objects (of different class) say PersonType1 and PersonType2 and trying to compare the fields are equal in the test case. The scenario is like:
jsonA -> PersonTypeA;
jsonB -> PersonTypeB;
both PersonTypeA.class and PersonTypeB.class have the same properties, say id, name, etc.
I am trying to assert the values are equal like this:
assertEquals(personA.getId(), personB.getId());
I am not able to use standard reflection equals provided by Mockito as the classes are not same.
I am not planning a write a bunch of extra code to compare the obejcts. Something more in the line of:
Assert.assertTrue(new ReflectionEquals(expected, excludeFields).matches(actual)); //mockito
to
Assert.assertTrue(compareProperties(expected, excludeFields).matches(actual));
Edit 1: This is not a duplicate question
I am trying to compare 2 different objects of different classes if they have the same value in properties which have the same name. I can write the code but looking for some existing util methods if already present in junit5, mockito, hamcrest, etc
assertEquals(objA.getId(), objB.getId());
//like this there are 30 properties
also there are nested objects like list, set of Strings. Comparing them manually is too much pain
Edit 2: Maybe this will explain better
I do not have control on the POJOs. They are owned by someone else. So, essentially if I have 2 classes
class Cat{
String id;
String name;
// 30 more properties
}
class Dog{
String id;
String name;
// 30 more properties
}
How to compare cat and dog have same values in id, name, etc. Because there are so many properties I do not want to write
assertEquals(cat.getId(), dog.getId());
So, is there any utility to do that? We can do the other way round, if we have 2 objects (of different classes) we can copy the properties using BeanUtils.copyProperies(o1, o2) in Spring and apache bean utils. Similarly is there a way to compare the properties?

There are many ways to achieve the goal, to name a few:
Option 1
Create your own Matcher and you'll be able to use something like this:
assertThat(actual, MyMatchers.semanticallyEqualsTo(expected));
Option 2
Create a custom method "compareProperties(expected, actual)" less BDD style but still can work
Option 3
Provide a converter method:
class PersonTypeA {
public PersonTypeB asTypeB() {
... if it has same properties, the conversion is trivial
return new PersonTypeB
}
}
and then use this method in test so that expected and actual will be of the same type and you can use a regular assertEquals
Option 4
Provide some type of "common representation for both objects". You've mentioned that they're somehow related to JSON, so you can probably present both values as some kind of JSON:
class PersonTypeA {
public JSONObject toJson() {...}
}
class PersonTypeB {
public JSONObject toJson();
}
Then in test you can compare JSON to JSON. Since its more complicated than a simple string comparison (JSON's pairs of key/value are unordered) you might need a JSON comparison library for tests. Something like jsonassert, there are others as well.
Notes:
Options 3 and 4 can also be implemented "externally" to PersonTypeA and PersonTypeB in some utility class.
Personally I would go with the first option, especially if you'll see that you face this issue in many tests because after all it allows to write the most clean test and also slightly better performance wise at least than option 4, no need to fiddle with JSON conversions.
But technically all the options are valid here

I did not get any solution but will write out what I did.
For same class object comparison, we can use Mockito ReflectionEquals like below. Follow the link for the original answer
assertTrue(new ReflectionEquals(deployments.get(0)).matches(returnedDeployments.get(0)));
https://stackoverflow.com/a/29793460/3497657
I saw because ReflectionEquals is an internal class it is better to use Hamcrest samePropertyValuesAs like this:
assertThat(returnedDeployments.get(0), samePropertyValuesAs(deployments.get(0)));
For objects of different class however I did not find anything so I had to write a Matcher myself
public class HasSameProperties<T> extends TypeSafeDiagnosingMatcher<T> {
private ClassA obj1;
public HasSameProperties(ClassA obj1) {
this.obj1 = obj1;
}
#Override
protected boolean matchesSafely(T item, Description mismatchDescription) {
if (item instanceof ClassA)
return matchClassA((ClassA) item);
return null;
}
public static Matcher<ClassB> hasSameProperties(ClassA objA) {
return new HasSameProperties(objA);
}
private boolean matchClassA(ClassB objB) {
assertThat(objB.getId(), equalTo(objA.getId()));
//other getters and setters
return true;
}

Related

Use a generic type to pass a specific class

I'm very new to programming language. My question might not even make sense. My environment is using java and trying to implement both ios and android apps in the same automation testing framework.
So, the idea is that any test script should be able to run on both the apps. Ex: one signin test script should be run for both ios and android.
I've decided to use interface and class implementation approach. The problem I'm facing is with test data. My company doesn't want to use excel. They want to use json for test data.
Here's my problem, look at the following line of code:
ValidBuy goodBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "good-buy.json", ValidBuy.class);
As you can see I have a class "ValidBuy" that has all the getters for a particular json file. I have another class "JsonFileReader" which takes the json filePath, fileName, and a class as an input and returns the data for that class name that I passed in. For this example I've passed ValidBuy.class
So, when I run a positive test, I'm passing "goodBuy" variable which is of type "ValidBuy". The problem starts here.
The test case is now specified with the data from goodBuy because it's type is "ValidBuy" and I'm passing goodBuy as a parameter.
Look at one of my extracted methods:
private void enterBuyInfo(ValidBuy goodBuy) {
itemPage = nativeApp.getItemPage(goodBuy);
itemPage.setItemName(goodBuy.getItemName());
itemPage.setItemSize(goodBuy.getItemSize());
itemPage.setItemDigitSSN(goodBuy.getSsn());
itemPage.clickContinue();
}
You can see those getters I'm using are coming from ValidBuy class.
If I run this test with the data for a badBuy:
InvalidBuy badBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "bad-buy.json", InvalidBuy.class);
It fails because now I have to change "ValidBuy" class with "InvalidBuy" class. Since, changing the parameter in the extracted method in every run is not possible, how can I make it more generic?
I want something like this:
TestData data = JsonFileReader.loadDaTa(RESOURCES_PATH, "good-client.json", InvalidBuy.class);
Here, TestData is generic. It could either be a class or interface (I don't know if that's possible) and the return type will be specified by whichever class I pass into the loadData() method. In this case InvalidBuy.class
The extracted method should look like this:
private void enterBuyInfo(TestData data) {
itemPage = nativeApp.getItemPage(data);
itemPage.setItemName(data.getItemName());
itemPage.setItemSize(data.getItemSize());
itemPage.setItemDigitSSN(data.getSsn());
itemPage.clickContinue();
}
If I can do this, I can use those extracted methods to create more tests.
I know I wrote a lot. I've only tried to make it as clear as possible. If it doesn't make any sense, just disregard it.
Any suggestions, ideas, code samples will be highly appreciated.
Firstly let me see if I understand your question. I think you are saying that loadData may return a value of type ValidBuy or InvalidBuy and you want to pass into it the class that you want returned. You then want to know how to use an interface that might represent either of these classes in your test methods so you can test various return values (both valid and invalid). You use the term "generic" in your question but I'm guessing you don't mean to use it in the specific way it's used in Java.
If I've understood your question correctly, then here's an answer:
Passing the class you wish to have returned into a method is an unusual usage and almost certainly not ideal. Better OOD would be to extract the common methods for all objects returned from loadData into an interface.
So:
interface Buy {
String getItemName();
boolean isValid();
}
class ValidBuy implements Buy {
#Override
public boolean isValid() {
return true;
}
...
}
class InvalidBuy implements Buy {
#Override
public boolean isValid() {
return false;
}
...
}
class JsonFileReader {
Buy loadData(Path path) {
...
}
}
Then your tests can look like:
#Test
void testValidBuy() {
assertTrue(reader.loadData(validPath).isvalid());
}
#Test
void testInvalidBuy() {
assertFalse(reader.loadData(invalidPath).isValid());
}
I realise I've simplified it a bit but hopefully you get the idea.

Spring Integration - aggregate and transform

What would be the simplest integration component arrangement in my use case:
Receive messages from multiple sources and in multiple formats (all messages are JSON serialized objects).
Store messages in buffer up to 10 seconds (aggregate)
Group messages by different class property getter (eg class1.someId(), class2.otherId(), ...)
Release all messages that are grouped and transform to new aggregated message.
So far (point 1. and 2.), I'm using aggregator, but don't know if there is out of box solution for problem at 3.) - or I will have to try to cast each Message and check if type of object is class1 - then use correlationstrategy someId, if class2 then otherId.
For problem 4.) - I could manually code something - but Transformer seems like a good component to use, I just don't know if there is something like aggregating transformer where I can specify mapping rules for each input type.
UPDATE
Something like this:
class One{
public String getA(){ return "1"; }
}
class Two{
public Integer getB(){ return 1; }
}
class ReduceTo{
public void setId(Integer id){}
public void setOne(One one){}
public void setTwo(Two two){}
}
public class ReducingAggregator {
#CorrelationStrategyMethod
public String strategy(One one){
return one.getA();
}
#CorrelationStrategyMethod
public String strategy(Two two){
return two.getB().toString();
}
#AggregatorMethod
public void reduce(ReduceTo out, One in){
out.setId(Integer.valueOf(in.getA()));
out.setOne(in);
}
#AggregatorMethod
public void reduce(ReduceTo out, Two in){
out.setId(in.getB());
out.setTwo(in);
}
}
Annotations have, I suppose, different use-case than current spring ones. RediceTo could be any object including collections. In config we could specify when passed first time should it be empty list or something else (like reduce in java streams).
Not sure what you would like to see as out-of-the-box solution. That is your classes, so your methods. How Framework may make some decision on them?
Well, yes, you need to implement CorrelationStrategy. Or you can consider to use ExpressionEvaluatingCorrelationStrategy and don't write the Java code :-).
Please, elaborate more what you would like to see as an out-of-the-box feature.
The aggregating transformer is encapsulated exactly in the MessageGroupProcessor function of the Aggregator. By default it is DefaultAggregatingMessageGroupProcessor. Yes, you can code your own or again - use an ExpressionEvaluatingMessageGroupProcessor and don't write Java code again :-)

Unit Testing and Mocking - Approach and Practice for Deeper Hierarchies - Junit and EasyMock

I have a hierarchical list of converters like the following for example:
#Named
public class NameConverter {
#Inject
private AddressConverter addressConverter;
public package2.Name convert(package1.Name source) {
package2.Name target = new package2.Name();
target.setFirstName(source.getName());
target.setLastName(source.getName());
target.setAddress(addressConverter.convert(source.getAddress()));
}
}
and AddressConverter has ZipCodeConverter and so on ...
In the Unit Testing class,
1) I would create a mock for addressConverter - EasyMock.createNiceMock.
2) Set the expectation -
EasyMock.expect(addressConverter.convert(EasyMock.anyObject(package1.Address.class))).andReturn(addressList); # What this addressList should be?
3) Whitebox.setInternalState for private fields.
Question :
I would assert on first name and last name if they are equal which is straight forward.
But, NameConverter is also responsible for setting the converted Address.There is a possibility for NameConverter to change the values of returned converted Address and other POJOs inside.
So how do I ensure through Asserts or something else, that NameConverter just sets the Address(and the POJOs encapsulated by it) as it is and does not tamper with the values ??
Possible Solution: In the EasyMock.expect return, should I create and set values for all POJOs till the last one in the hierarchy and assert on each of the values?
But that doesn't seem like unit testing !!
Please help as how to unit test this converter.
It is unit testing to set the return value of a mock object and to assert that that return value is put in the right place by your NameConverter.
However, perhaps what you're coming across is a failure of appropriate layering. If you have a set of 'converter' classes which then need to be co-ordinated in some fashion you may want to make each converter independent and to bring the co-ordination responsibility elsewhere. So, your NameConverter should be completely independent of AddressConverter and you perhaps need a third class which is responsible for calling a set of converters, which each just do their job. You could restructure each converter to be given an instance of both their input and output object and their unit tests assert that they only act on known fields within each object. Then the co-ordinator object doesn't need to know anything about what each converter does, it just needs to locate / create instances of the input and output objects and to call each converter in turn. That's very amenable to a unit-testing approach, without resulting in a lot of layering concerns.
Example code:
public interface Converter<S, T> {
convert(S source, T target);
}
public class NameConverter implements Converter<p1.Name, p2.Name> {
#Override
public void convert(p1.Name source, p2.Name target) {
target.setFirstName(source.getName());
target.setLastName(source.getName());
}
}
public class AddressConverter implements Converter<p1.Name, p2.Name> {
#Override
public void convert(p1.Name source, p2.Name target) {
// more stuff.
}
}
public class ConversionService {
private final Set<Converter> converters;
#Inject
public ConversionService(Set<Converter> converters) {
this.converters = converters;
}
public p2.Name convert(p1.Name source) {
p2.Name target = new p2.Name();
converters.forEach((converter) -> converter.convert(source, target);
return target;
}
}
Then your unit test really just need to know that all your lower-level converters were called.
I would suggest three options:
Return a new empty instance of address from your mock and compare that the same exact instance is set to the target. Don't test if the address value is modified. It's Ok not to test every single possibility of things going wrong.
Return a strict mock of address without any expectations set. It will throw if there is an attempt to modify it. And again check for instance equality.
Don't use mocks at all. Test the entire hierarchy as a whole. It does not look like unit testing, but it may be a good option. I think mocks are often overused and should be avoided when possible. Please see more here.
I would recommend the following as a good unit test for NameConverter:
public final class NameConverterTest {
#SUT
NameConverter tested;
#Test
public void convertNameFromPackage1ToNameFromPackage2() {
Address address = new Address();
package1.Name source = new package1.Name("A Name", address);
package2.Name converted = tested.convert(source);
assertEquals(source.getName(), converted.getFirstName());
assertEquals(source.getName(), converted.getLastName());
assertNotNull(converted.getAddress());
}
}
According to Martin Fowler's definition, the above is still a unit test for the NameConverter unit, even if it doesn't isolate it from its dependency on AddressConverter (which would have its own unit test).
(For simplicity, I used an hypothetical #SUT annotation which takes care of instantiating the "system under test" with injected dependencies - and actual testing libraries for this do exist.)

Custom object filter for a grid column in sencha GXT

Important edit: I added a depth level to the situation to better reflect my problem.
I have a GXT Grid with a ListStore of a certain type Foo. Foo happens to have some important object properties, including one of type Bar. Type Bar consists of two object properties: fooFoo of type FooFoo and barBar of type Barbar. These two can be null and have a String property description.
I want to use the GXT grid's filtering to filter the Foo object records' by their Bar value's FooFoo or BarBar description.
I tried to add a ValueProvider<Foo, String> barDescription(); to FooProperties, resulting in:
StringFilter<Foo> barbarFilter = new StringFilter<Foo>(fooProps.barbarDescription());
In which Foo#getBarBarDescription() is implemented as follows:
public String getBarBarDescription() {
return this.getBar().getBarBar().getDescription();
}
Is there a simple/convenient way to implement this behaviour in GXT? I have not found it.
The implementation I describe above is the one I have tried, but the filters don't show up in the grid at all, no further error messages.
In response to Colin's answer to the previous version of my question, I have tried the following:
#Path("bar.barbar.description")
ValueProvider<Foo, String> barbarDescription();
Hoping for it to call Foo#getBar().getBarBar().getDescription(). I suspect the possibility for FooFoo and BarBar to be null may be causing issues.
If you want to have barDescription() invoke getBar().getDescription() on your Foo objects, then try this:
public interface FooProperties extends PropertyAccess<Foo> {
#Path("bar.description")
ValueProvider<Foo, String> barDescription();
//...
}
The #Path annotation works the same here as it does in the editor framework - you can use it to specify the path to the property you want access to. This allows you to skip creating a getBarDescription() method in your own Foo object.
Another option is to just build your own ValueProvider implementation. Using PropertyAccess is a way to ask the compiler to do the work for you, but nothing stops you from doing it yourself. In this case, it might look like this:
public class FooBarDescriptionValueProvider implements ValueProvider<Foo, String> {
public String getValue(Foo object) {
//TOOD consider a object.getBar() null check?
return object.getBar().getDescription();
}
public void setValue(Foo object, String value) {
object.getBar().setDescription(value);
}
public String getPath() {
return "bar.description";
}
}
Note that this is almost exactly what the PropertyAccess generated version will look like, but it allows you to customize the behavior however you want.

How to print Java Bean completely using reflection or any other utility

I have an Java bean class Person containing 3 variables:
name (String)
age (String)
address (Object).
Address contains 3 variables:
street
door_no
city
I would like to have a utility which should print all variables in Person.
By this I mean it should print Person & also the Address object contained in it.
I could create a hashmap and put the variable names & values using reflection and print key/value UI in JSP but the issue is I have to apply reflection for Address to add variable/value in the hashmap.
Is there a utility available to do this?
You could use ToStringBuilder from Apache Commons.
From documentation:
A typical invocation for this method would look like:
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
More details:
This class enables a good and consistent toString() to be built for
any class or object. This class aims to simplify the process by:
allowing field names handling all types consistently handling nulls
consistently outputting arrays and multi-dimensional arrays enabling
the detail level to be controlled for Objects and Collections handling
class hierarchies To use this class write code as follows:
public class Person {
String name;
int age;
boolean smoker;
...
public String toString() {
return new ToStringBuilder(this).
append("name", name).
append("age", age).
append("smoker", smoker).
toString();
}
}
Alternatively, there is a method that uses reflection to determine the
fields to test. Because these fields are usually private, the method,
reflectionToString, uses AccessibleObject.setAccessible to change the
visibility of the fields. This will fail under a security manager,
unless the appropriate permissions are set up correctly. It is also
slower than testing explicitly.
A typical invocation for this method would look like:
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
You're probably looking for Apache Commons ToStringBuilder#reflectionToString(Object).
You may find the Jackson JSON serializer useful for this purpose. The Jackson library may already be part of your stack. If not, find the required dependencies below.
private static final ObjectMapper OBJECT_MAPPER_SINGLETON = new ObjectMapper();
public static String toStringUsingJackson(final Object object) {
try {
return OBJECT_MAPPER_SINGLETON.writeValueAsString(object);
} catch (final JsonProcessingException e) {
return String.valueOf(object);
}
}
Sample output:
{"name":"John Doe","age":42}
Required maven/gradle dependencies:
jackson-core, groupId=com.fasterxml.jackson.core
jackson-databind, groupId=com.fasterxml.jackson.core
You can implement the toString method to print out whatever you want, or you can use Apache Commons ToStringBuilder http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/builder/ToStringBuilder.html and its reflectionToString method. I don't believe this will recurse through the properties (like address for example), but if you want to see Address printed out with Street, Door No and City, use implement its toString method to print that information out.

Categories