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 :-)
Related
The code goes like this:
#AllArgsConstructor // lombok
class Message1 {
ByteBuffer byteBuffer;
// Wrap a bytebuffer
public static Message1 wrap(ByteBuffer b) { return new Message1(b); }
public int getVal1() { return byteBuffer.getInt(0); }
public void setVal1(int val1) { byteBuffer.put(0, val1); }
public int getVal2() { return byteBuffer.getShort(6); }
public void setVal1(short val2) { byteBuffer.put(6, val2); }
...
// more get and set of primitive types.
}
Can I have an annotation where I can do something like:
#MsgField(name="Val1", type="int", index=0)
#MsgField(name="Val2", type="short", index=6)
class Message1 {
ByteBuffer byteBuffer;
// Wrap a bytebuffer
public static Message1 wrap(ByteBuffer b) { return new Message1(b); }
}
I am trying to read messages from a network tcp socket and use the offsets to read specific messages and their fields.
Lombok probably won't be able to help here, however consider the following solution:
Create a non-java file that will act as a kind of DSL with all the relevant definitions (basically the data that you have in the annotation). It can be properties file, json, xml or any other format that can be easily parsed
Create an annotation processor (pretty much like a lombok itself) that will read these DSL files, parse the information in these files, and based on this information, will generate proper Java Classes with all the relevant methods.
All this will happen during the compile time
Compile the java classes together with the other sources.
To implement the 'step 2' consider using the third-party tools - you don't really have to do it "from scratch". Example of such a library that I used once Java Poet
The main idea of this approach is generating the whole set of classes like class Message1 in your example. Since the DSL files are not java files by themselves, you won't need to face all the complexity of different syntax in different java versions that Lombok has to deal with, so it will be way more simple that the Lombok implementation.
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;
}
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.
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.)
Say I follow the Single Responsibility Principle and I have the following classes.
public class Extractor {
public Container extract(List<Container> list) {
... some extraction
}
}
public class Converter {
public String convert(Container container) {
... some conversion
}
}
As you can see it's following the principle and all the names of the classes/methods tell what they do. Now I have another class that has a method like this.
public class SomeClass {
private Extractor extractor = new Extractor();
private Converter converter = new Converter();
private Queue queue = new Queue();
public void someMethod(List<Container> list) {
Container tmp = extractor.extract(list);
String result = converter.convert(tmp);
queue.add(result);
}
}
As you can see the "someMethod"-Method does call extract, convert and add. My question is now, how do you call such a class/method? It's not actually extracting, converting or adding but it's calling those?
If you name the method after its responsibility what would that be?
Well since you seem to add to a queue and you don't return anything I'd call it addToQueue. The fact that you convert + extract is implementation detail that I don't think needs to be exposed.
What about processAndQueueMessage?
Also (not related), you shouldn't create (using new) the Extractor and Converter in your SomeClass, you should rather inject them (at construction or in setters), and use interfaces to them. That will make it easier to test, and reduce coupling between implementations.
// Assuming Converter and Extractor are interfaces to the actual implementations
public class SomeClass {
private final Extractor extractor ;
private final Converter converter;
private Queue queue = new Queue();
public SomeClass(Extractor extractor, Converter converter) {
this.converter = converter;
this.extractor = extractor;
}
public void someMethod(List<Container> list) {
Container tmp = extractor.extract(list);
String result = converter.convert(tmp);
queue.add(result);
}
}
And you create it using:
final SomeClass myProcessor = new SomeClass(new MyExtractorImplementation(), new MyConverterImplementation());
(Or use a DI container, like Spring or Pico)
What you do is think about the composite meaning of the sequence of method calls, turn that into a concise verb or verb phrase and use that as the name. If you can't come up with a concise name then you could use a generic / neutral name (like "process") or use something completely bogus (like "sploddify").
If you want the name to be really generic, I'd go with addToQueue() or populateQueue() since getting something into that object seems to be the point of the method.
But really at that level I'd call it by what business logic it's trying to accomplish, in which case the name really depends on what it's being used for.
If you can't come up with a good name, it is an indication that your procedural abstraction is rather arbitrary / artificial, and a possible hint that there might be a better way to do it. Or maybe not.
Sounds like some kind of builder class. You get data in one format, convert it and then create some kind of output format. So how about "SomethingSomethingBuilder"?
I'm assuming someone downvoted me because I forgot to provide a good name for the method. Sorry about that.
So this method adds incrementally data into your builder class. I would call it, "Add", "AddData" or "Push" (I'd probably go with push because that has very similar meaning in many standard classes).
Alternative to "Builder" could potentially be "SomeKindOfCreator". Obviously you would name it based on whatever it is your class is actually creating.