Mockito test cases for foreach loop - java

I have an arraylist and I am converting it into another arraylist of different type using foreach loop. I want to write test cases using mockito. How can I do it?
List<Product1> list1 = new ArrayList<Product1>();
List<Product2> list2 = new ArrayList<Product2>();
list1.foreach(productList1 -> list2.add(new Product2(product1.getName())));
class Product1{
}
class Product2{
String name;
public Product2(String name){
this.name=name;
}
}

You dont' need mocking here. You can write a simple test such as
#Test
public void testListConversionForEmpty() {
assertThat(theConvertingMethod(emptyListOfProduct1), is(emptyListOfProduct2));
}
And then you go in, and add more test methods that act on lists with real content.
In other words: you only use mocking frameworks when creating "real" objects is too complicated.
In your case, you should simply instantiate a few Product1 and Product2 objects, put them into lists, and make sure that your conversion code delivers the expected results. Meaning: you can fully control the input without mocking anything.
( for the record: is() up there is a hamcrest matcher )

Related

How can I unit test a method with multiple internal calls to class I want to mock using EasyMock

I would like to unit test a method with multiple internal calls to a class I want to mock using EasyMock.
The test method actually runs 5 times and calls the mocked method.
During each loop, I will create some objects, all of the same class (let's say of class A).
The private method will call the mock object method that takes the instance of class A, evaluate it and return a result.
In the end, the public method will return a List of results.
I tried the standard EasyMock.expect(MockClass.method(A)).andReturn() but it does not work since there is no implementation of equals() for class A:
// this is the method example I am trying to test
public methodToTest(){
// some logic
privateMethodToTest(x);
// some logic
}
private List<B> privateMethodToTest(int x){
List<B> list = new ArrayList<>();
List<A> all = getObjects(x); //getObjects private method
for (A a:all){
list.add(objectToMock.methodToMock(a));
return list;
}
This is how I would like it to work:
EasyMock.createMock(ObjectToMock.class);
EasyMock.expect(ObjectToMock.methodToMock(A)/* when A.getValue() == 1 */.andReturn("B object number 1")
EasyMock.expect(ObjectToMock.methodToMock(A)/* when A.getValue() == 2 */.andReturn("B object number 2")
//... and so on
//object of class A does not implement equals()
I am not sure how to do it and I was not able to find any similar example or answer to my question.
You need another matcher. By default, EasyMock will indeed match using equals. But you can't do that. Your basic choices are:
You don't care about matching precisely
If seems to be the easiest for you. It means doing:
expect(objectToMock.methodToMock(anyObject()).andReturn("B object number 1");
expect(objectToMock.methodToMock(anyObject()).andReturn("B object number 2");
Use a comparator
According to your comment, you might actually prefer this
expect(mock.methodToTest(EasyMock.cmp(new A(1), Comparator.comparingInt(A::getValue), LogicalOperator.EQUAL))).andReturn(1);
The only problem is that you need a A with the correct value to compare with.
To have a simplified version, you can use your own matcher
The expectation using the custom matcher right below.
expect(mock.methodToTest(cmp(0))).andReturn(3);
public static <T> T cmp(int value) {
reportMatcher(new IArgumentMatcher() {
#Override
public boolean matches(Object argument) {
return value == ((A) argument).getValue();
}
#Override
public void appendTo(StringBuffer buffer) {
buffer.append("A.value=").append(value);
}
});
return null;
}
When unittesting we verify public observable behavior of the code under test, that is return values and communication with dependencies.
Anything else is implementation detail which we do not test. The reason is that you might want to refactor your code. That means you want to improve the structure of your code without changing its behavior. Your unittest schould verify that you did not change behavior accidentally. But they can only do this if you do not have to change them too.

Mockito mock object with list argument's contents

I've faced this situation pretty often and don't know how to resolve it using Mockito's default methods such as (any, anyList, eq)
For example I have an object where I want to mock a method expecting a list which contains other mocked objects. Let me explain:
public class MyMapper {
public List<DataObjects> convertList(List<String> rawContents) {
rawContents.stream().map(r -> convertObject(r))
.collect(Collectors.toList());
}
public DataObject convertObject(String rawContent) {
return new DataObject(rawContent);
}
}
public class MyWorkerClass {
public boolean start(List<String> rawContents) {
List<DataObject> objects = new MyMapper().convertList(rawContents);
return publish(objects);
}
public boolean result publish(List<DataObject> objects) {
../// some logic
}
}
Now what I want to assert is something like. Note: Please assume the right mocks are returned when new() is called [Using some PowerMockito]
#Test
public void test() {
String content = "content";
DataObject mock1 = Mockito.mock(DataObject.class);
MyMapper mapperMock = Mockito.mock(MyMapper.class);
MyWorkerClass worker = new MyWorkerClass();
Mockito.when(mapperMock.convertObject(content)).thenReturn(mock1);
Mockito.when(worker.publish(eq(Arrays.asList(mock1)).thenReturn(true);
boolean result = worker.start(Arrays.asList(content));
Assert.assertTrue(result);
}
The problem with the code above is in the line
Mockito.when(worker.publish(eq(Arrays.asList(mock1)).thenReturn(true);
This will try to match the list object instead of the list contents, in other words, even when I have to lists A: [mock1] and B: [mock1], A is not equal to B and ultimately the stubbing fails.
What I need is some sort of matcher similar to hamcrest's contain matcher. Something like:
Mockito.when(worker.publish(contains(mock1)).thenReturn(true));
Is there anyway I can achieve this? Keep in mind the code above is just an example to grasp the problem, the real situation is a little bit more complex and I can only mock individual objects, not the list itself
Thanks
Nevermind, later I learned that Mockito's eq() method will call the equals() method on the argument. Now if that is an ArrayList it means it will return true if two list sizes are equal and if the equal's comparison for each one of the elements in the list also returns true. See https://docs.oracle.com/javase/6/docs/api/java/util/List.html#equals%28java.lang.Object%29
And for even more customization argThat() could be used What's the difference between Mockito Matchers isA, any, eq, and same?

OO pattern for dividing a collection into groups

I have a list of MyObjects which I need to divide into three groups:
Known good (keep)
Known bad (reject)
Unrecognized (raise alert)
MyObject contains various properties which must be examined to determine which of the 3 groups to put the object in.
My initial implementation (Java) just takes a List in its constructor and does the triage there. Pseudocode:
class MyObjectFilterer {
public MyObjectFilterer(List<MyObject> list) {
// triage items here
}
public List<MyObject> getGood() {
// return sub-list of good items
}
public List<MyObject> getBad() {
// return sub-list of bad items
}
public List<MyObject> getUnrecognized() {
// return sub-list of unrecognized items
}
}
Any issues with this implementation? Is there a better OO choice?
I would probably prefer a static factory method to do the filtering, that then calls a private constructor that takes the three filtered lists, following the good code practice of never doing any serious work in a constructor. Other than that, this looks fine.
There may be multiple approachs. If the problem is generic / repetitive enough, you could define an interface with a method to classify the objects.
interface Selector {
public boolean isGood(MyObject myObject);
public boolean isBad(MyObject myObject);
public boolean isUnknown(MyObject myObject);
}
That way you could change the logic implementation easily.
An other idea would be using the Chain of responsibility.
Your MyObjectFilterer contains a reference to three Objects GoodFilterer, BadFilterer and UnrecognizedFilterer. Each of them contains the following methods: addMethod(MyObject object), getObjects() and addFilter(). Of course they have to implement an interface Filterer.
With the addFilter method you can build the chain. so that the GoodFilterer contains a reference to the BadFilterer and this one contains a reference to the UnrecognizedFilterer
Now you go through your list of MyObjects and call the add method on the GoodFilterer (first one in this chain). Inside the add method you decide if this is good, than you keep it and finish the work, if not pass it on to the BadFilterer.
You keep your three methods for getting the good/bad and unrecognized, but you will pass this to the getObjects() method of the corresponding Filterer
The Benefit is that the logic if this is a good/bad or Unrecognized one is now seperated.
The Downside you would need 3 new classes and 1 Interface.
But like i said, this is just an other idea what you could do.
You should simplify as it's possible. Just make static method in MyObjectFilter with following signature:
public static List filterMyObjects(List data, Group group).
Group is enumeration with three values and it can be used as attribute of MyObject class
I might try something like:
enum MyObjectStatus {
GOOD, BAD, UNRECOGNIZED;
}
class MyObjectFilterer {
private MyObjectStatus getStatus(MyObject obj) {
// classify logic here, returns appropriate enum value
}
// ListMultimap return type below is from Google Guava
public ListMultimap<MyObjectStatus, MyObject> classify(List<MyObject> objects) {
ListMultimap<MyObjectStatus, MyObject> map = ArrayListMultimap.create();
for(MyObject obj: objects) {
map.put(getStatus(obj), obj);
}
}
}
Call classify() to get a Multimap, and extract each category as needed with something like:
List<MyObject> good = map.get(GOOD);
List<MyObject> bad = map.get(BAD);
List<MyObject> unknown = map.get(UNRECOGNIZED);
A nice thing about this solution is you don't have to create/publish accessor methods for each category (unless you want to), and if new categories are created, you also don't add new accessors -- just the new enum and the additional classifier logic.

how to test this portion of code

Hello I'm writting junit test how can I test this method .. this is only part of this method :
public MyClass{
public void myMethod(){
List<myObject> list = readData();
}
}
How will I make the test for this? ReadData is a private method inside MyClass?
You can always test the List object to see if it contains all of the elements that readData() is supposed to insert into the list. Make a public method that returns the list and you can compare the length and elements in that list to what you are expecting to be in there.
As written, it doesn't make sense to test myMethod() unless readData() changes the instance state the way Frank Grimm mentioned. One thing to do would be to change myMethod() so that it puts list into a List instance variable. Then you might do something like this:
#Test
public void testThatReadDataReturnsACorrectList(){
MyClass inst = new MyClass(); // Add args to ctor call if needed - maybe a file path that readData() will use?
inst.myMethod();
// Create a list of MyClasses that match what you expect readData() to return:
List<MyClass> expectedList = new List<>();
expectedList.Add(new MyClass(/* Some arguments */));
expectedList.Add(new MyClass(/* Some more arguments */));
expectedList.Add(new MyClass(/* Some other arguments */));
// Assert that the list you created matches the list you get back from
assertArrayEquals("Did not get the list expected", expectedList.ToArray(), inst.getList().ToArray());
}
You'd still have to write MyClass.getList() to return the List instance variable.
To be robust, you could make the MyClass constructor accept an object that implements an interface like IMyReadInterface. readData() would use that object. Then in your test, you could instantiate a mock that also implements IMyReadInterface, configure the mock to provide the data needed so that readData() works correctly, and construct inst with that mock.
Unless we know more about the method, all you really need to test is that the return from readData is in a format that fits into your generic list. Otherwise, its hard to recommend anything without knowing more about whats going on in your private method.

Can Java store methods in arrays?

Well I wrote some code and all I was doing was for loops, but changing which method I called. I tried using a for loop so it'd be a bit neater (and out of curiosity to see if it could be done), but it doesn't compile when I do it this way, because it doesn't recognize an item in an array as a method, I think. This is what I have:
String[] moveArray = {moveRight,moveDown,moveLeft,moveUp};
for (i = 0; i < 4; i++) {
while (myWumpus.moveArray[i]) {
myWumpus.moveArray[i];
generator.updateDisplay();
}
}
When I try compile I get
not a statement myWumpus.moveArray[i]();
';' expected myWumpus.moveArray[i]();
(It refers to the first statement in the while loop)
So, I think it's maybe because I'm making it an Array of type String? Is there a type Method? Is this at all possible? Any solutions welcome :). Also, I can get it to work using 4 while loops, so you don't need to show me that solution.
You cannot store methods directly in arrays. However you can store objects, which implement the same method differently. For example:
Mover[] moveArray = {new RightMover(), new DownMover() new LeftMover(), new UpMover() };
for (i = 0; i < 4; i++) {
while (myWumpus.moveArray[i]) {
moveArray[i].move();
generator.updateDisplay();
}
}
Yes, you can store methods in arrays using Reflection, however it is likely that what you actually want to do in this situation is use polymorphism.
As an example of polymorphism in relation to your problem - say you created an interface as follows:
public interface MoveCommand {
void move();
}
You can then create implementations as follows:
public class MoveLeftCommand implements MoveCommand {
public void move() {
System.out.println("LEFT");
}
}
etc. for the other move options. You could then store these in an MoveCommand[] or collection like a List<MoveCommand>, and then iterate over the array/collection calling move() on each element, for example:
public class Main {
public static void main(String[] args) {
List<MoveCommand> commands = new ArrayList<MoveCommand>();
commands.add(new MoveLeftCommand());
commands.add(new MoveRightCommand());
commands.add(new MoveLeftCommand());
for (MoveCommand command:commands) {
command.move();
}
}
}
Polymorphism is very powerful, and the above is a very simple example of something called the Command Pattern. Enjoy the rest of your Wumpus World implementation :)
You can't store methods in arrays in Java, because methods aren't first-class objects in Java. It's a reason some people prefer to use other languages like Python, Scheme, etc.
The work-around is to create an interface which contains one method, then create four classes implementing that interface - the MoveRight, MoveLeft, etc... classes. Then you can store instances of those classes in your array and call them all the same way.
You can't call methods like that. But you can using reflection:
Just change the first line in the while-loop to:
Method m = myWumps.getClass().getMethod(moveArray[i]); // if the method is void
m.invoke(myWumps);
(you will have to declare/catch a few exceptions)
But you'd better avoid reflection, and use the Command pattern instead.
Updated answer for Java 8 and onwards-
Since the introduction of lambda expressions and method references in Java 8, storing various methods in variables is now possible. One main issue is that arrays don't currently support generic objects in Java, which makes storing the methods in arrays less doable. However they can be stored in other data structures like a List.
So for some simple examples you can write something like:
List<Comparator<String>> stringComparators = new ArrayList<>();
Comparator<String> comp1 = (s1, s2) -> Integer.compare(s1.length(), s2.length());
stringComparators.add(comp1);
or
List<Consumer<String>> consumers = new ArrayList<>();
Consumer<String> consumer1 = System.out::println;
consumers.add(consumer1);
and then loop/iterate through the List to get the methods.

Categories