mockito matchers for Optional<String> and Map<String, String[]> - mockito

New to Junit, Please help me find mockito matchers for Optional and Map<String, String[]>.
public Model<SummaryModel> getAll(Map<String, String[]> queryParameters, Integer page,
Integer limit, Optional<String> sort) throws PageNumberOutOfBoundsException;
when(service.getAll( any(), anyInt(),anyInt(), any())).thenReturn(mockedResource);

We have different options, based on our requirement we can use the same. Below is some example of Optional and Map<String, String[]>.
For Map<String, String[]>
You can create your actual map with values and then pass like Mockito.eq(myMap);
You can use Mockito.anyMap()
For Optional
Mockito.eq(Optional.ofNullable(sort))
Mockito.any(Optional.class)

Related

Issue with Mockito.Any for overloaded methods

I have two methods in my Java class as below
Method 1:
public ResponseEntity<T> callMethod(String param1,Map<String, String> param2, Object param3,HttpMethod param4,Class<T> param5)
Method 2
public ResponseEntity<T> callMethod(Map<String, String> param1, Object param2,
HttpMethod param3, Map<String, ?> param4,
final Class<T> param5) {
I have written a unit test case where when i try to call the method as below
callMethod(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
eq(ServiceResponse.class))).thenReturn(responseEntity)
it fails with the below error
reference to callMethod is ambiguous
both method callMethod
(java.util.Map<java.lang.String,java.lang.String>,B,org.springframework.http.HttpMethod,java.util.Map<java.lang.String,?>,java.lang.Class)
and method
callMethod(java.lang.String,java.util.Map<java.lang.String,java.lang.String>,B,org.springframework.http.HttpMethod,java.lang.Class)
match
How can this be resolved. There are many unit test cases and i want to fix the class than the unit test cases. Is there a way?
Yes, you can put types in the any() like any(MyClass.class) there are also some built in ones. If you want to call your first method you can use the anyString() and anyMap() ones.
callMethod(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.any(HttpMethod.class), eq(ServiceResponse.class))).thenReturn(responseEntity)

How is this Map of String to String possible as a Map of String to a list of String in Groovy?

Saw some working code in a project that is like the one below (of course that's just an example) but I'm extremely confused at how this is possible as a Map<String, String> and not Map<String, List<String>>?
Looked it up in the Groovy doc but I didn't see anything that explains this concept. Could someone explain if this is indeed a legit concept in Groovy?
static final Map<String, String> NAMES = [
"Male": ["Bill", "Bryant", "Jack"],
"Female": ["Lily", "Haley", "Mary"]
]
It happens because of Java's Generic Type Erasure. If you look at the internal type signatures, you will see that NAMES field is just a type of java.util.Map. Take a look at the descriptor of that field.
$ javap -s -p SomeClass
Compiled from "SomeClass.groovy"
public class SomeClass implements groovy.lang.GroovyObject {
private static final java.util.Map<java.lang.String, java.lang.String> NAMES;
descriptor: Ljava/util/Map;
private static org.codehaus.groovy.reflection.ClassInfo $staticClassInfo;
descriptor: Lorg/codehaus/groovy/reflection/ClassInfo;
public static transient boolean __$stMC;
descriptor: Z
private transient groovy.lang.MetaClass metaClass;
descriptor: Lgroovy/lang/MetaClass;
private static java.lang.ref.SoftReference $callSiteArray;
descriptor: Ljava/lang/ref/SoftReference;
public SomeClass();
descriptor: ()V
public static void main(java.lang.String...);
descriptor: ([Ljava/lang/String;)V
protected groovy.lang.MetaClass $getStaticMetaClass();
descriptor: ()Lgroovy/lang/MetaClass;
public groovy.lang.MetaClass getMetaClass();
descriptor: ()Lgroovy/lang/MetaClass;
public void setMetaClass(groovy.lang.MetaClass);
descriptor: (Lgroovy/lang/MetaClass;)V
static {};
descriptor: ()V
public static java.util.Map<java.lang.String, java.lang.String> getNAMES();
descriptor: ()Ljava/util/Map;
private static void $createCallSiteArray_1(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
private static org.codehaus.groovy.runtime.callsite.CallSiteArray $createCallSiteArray();
descriptor: ()Lorg/codehaus/groovy/runtime/callsite/CallSiteArray;
private static org.codehaus.groovy.runtime.callsite.CallSite[] $getCallSiteArray();
descriptor: ()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
}
Now, that' not all. If you decompile the Groovy bytecode to the Java readable code, you will find something like this.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.Generated;
import java.util.Map;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class SomeClass implements GroovyObject {
private static final Map<String, String> NAMES;
#Generated
public SomeClass() {
CallSite[] var1 = $getCallSiteArray();
super();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].callStatic(SomeClass.class, var1[1].call(NAMES));
}
static {
Map var0 = ScriptBytecodeAdapter.createMap(new Object[]{"Male", ScriptBytecodeAdapter.createList(new Object[]{"Bill", "Bryant", "Jack"}), "Female", ScriptBytecodeAdapter.createList(new Object[]{"Lily", "Haley", "Mary"})});
NAMES = var0;
}
#Generated
public static Map<String, String> getNAMES() {
return NAMES;
}
}
At this level, NAMES field signature matches Map<String, String>. But look at the static constructor and how this field gets initialized. The NAMES field of type Map<String, String> gets initialized with a raw Map type. Also, the ScriptBytecodeAdapter.createMap method returns a raw map, but it could return a parameterized map as well - you will see the same effect. If that map wasn't a raw map, the compiler would complain and throw an error because of incompatible types. But a raw map essentially allows you to assign a map that stores values that are incompatible with the parameters.
You can get the same effect in pure Java. Take a look at the following example:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
final class SomeJavaClass {
private static final Map<String, String> NAMES;
static {
final Map map = new HashMap();
map.put("Male", Arrays.asList("Bill", "Brian", "Jack"));
NAMES = map;
}
public static void main(String[] args) {
System.out.println(NAMES);
System.out.println(((Object) NAMES.get("Male")).getClass());
}
}
When we execute its main method, we will get the following output:
{Male=[Bill, Brian, Jack]}
class java.util.Arrays$ArrayList
In this example, we had to cast NAMES.get("Male") to Object, because otherwise, we would get a ClassCastException - an ArrayList cannot be cast to String. But when you cast to Object explicitly, you can get an ArrayList from a map that, by definition, should keep only string values.
This is known Java behavior - generic types get erased so the raw types can be compatible with pre Java 1.5 versions. Groovy for its dynamic capabilities operates often on raw classes like Map, or List, and thus it can silently overcome some of those limitations.
If you want to use more restricted type checks, you can use #groovy.transform.TypeChecked annotation to keep Groovy's dynamic behavior and add more restrictive type checks. With this annotation added, your class won't compile anymore.

Can marshalling and unmarshalling behave differently?

With this object for example :
public class Person {
#XmlAttribute
private String name = null;
#XmlElement
private Address address = null;
// getters and setters
}
XML file :
<person name="blabla">
<address>...</address>
</person>
What can I do if I want to load a complete Person object (name + address) when umarshalling but only saving its name when marshalling ? (i.e. not saving the address)
The easiest would be to make a copy and remove unnecessary data.
Another (much more complicated option) option would be to defined different mappings. This is possible with MOXy:
Map<String, Object> tenantOneProps = new HashMap<String, Object>();
ArrayList tenantOneBindings = new ArrayList();
tenantOneBindings.add("examples/virtual/base-bindings.xml");
tenantOneBindings.add("examples/virtual/binding-tenant1.xml");
tenantOneProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantOneBindings);
JAXBContext tentantOneContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantOneProps);
Map<String, Object> tenantTwoProps= new HashMap<String, Object>();
ArrayList tenantTwoBindings = new ArrayList();
tenantTwoBindings.add("examples/virtual/base-bindings.xml");
tenantTwoBindings.add("examples/virtual/binding-tenant2.xml");
tenantTwoProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantTwoBindings);
JAXBContext tentantTwoContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantTwoProps);
Here you define two sets of mappings - base plus either tenant1 or tenant2. Thus you create two contexts. You can unmarshal with one and marshal with another.

Mockito verify method was called with set, that contains specific value

I want to be sure that mocked is called with specific set of strings as parameter.
For example, I have the following code:
public class SomeLogic {
#Autowired
private SpecificService specificService;
public void action() {
Set<String> args = fillArgsMethod();
specificService.handleArgs(args);
}
}
And my current try to test it is the following
#Mock
private SpecificService specificService
#InjectMocks
private SomeLogic someLogic;
#Test
public void testAction() {
someLogic.action();
verify(specificService).handleArgs(anySet());
}
But I want to be sure, that handleArgs() will receive the exact set of strings, that I expect. How can I modify verifying to check that handleArgs is called with set "first","second"?
Thanks
Isah gave a valid answer, but I want to turn your attention to a more general feature of Mockito which is ArgumentCaptor
In you case you would do something along the following lines:
Class<HashSet<String>> setClass = (Class<HashSet<String>>)(Class)HashSet.class;
ArgumentCaptor<Set<String>> setCaptor= ArgumentCaptor.forClass(setClass .class);
verify(specificService).create(setCaptor.capture());
HashSet<String> capturedSet = setCaptor.getValue();
//do whatever test you want with capturedSet
Prepare your Set parameters before calling the test method
#Test
public void testAction() {
Set<String> expectedParams = new HashSet(Arrays.asList("first", "second");
//call tested method
verify(specificService).handleArgs(expectedParams);
}
isah's solution is perfect for you if you want to confirm that the set contains exactly the two items you specify; Mockito compares using .equals by default, and Set.equals is defined as refer to equal elements in any order.
For a more-flexible "contains" test that matches your question title, that allows for set members beyond your expected values, you can also use the Hamcrest contains matcher:
someLogic.action();
verify(specificService).handleArgs(argThat(contains("first", "second")));
At least, that's how it should look. Unfortunately, argThat infers its return type from the Matcher, which infers its return type from the arguments, so Java assumes your first argument is not a Set<String> but a Iterable<capture#1-of ? extends String>. You'll need to cast explicitly and suppress warnings to get it to work:
// requires #SuppressWarnings("unchecked")
verify(specificService).handleArgs(
(Set<String>) argThat(contains("first", "second")));

ValueInjecter - converting some properties of source into a list in target

Just started using Value Injector: http://valueinjecter.codeplex.com/, and I have a question:
I have a Source class that has many properties. Some properties have a common suffix of "Profile". These properties are not always String, but mostly are. Target has 1 property, Dictionary<string, string>. I would like all properties that end with "Profile" to be inserted into the Dictionary<string, string> with key = PropertyName and value = Property's value. I think it can be done but the documentation isn't very clear to me. Can someone point me to the right direction? Thanks!
Sorry I have no experience with Value Injector, but if you chose to use AutoMapper you would most likely use a Custom Resolver:
Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.Profile, opt => opt.ResolveUsing<ProfileResolver>());
Where the resolver would look something like:
public class ProfileResolver : ValueResolver<Source, Dictionary<string, string>>
{
protected override int ResolveCore(Source source)
{
var rc = new Dictionary<string, string>();
// Do some funky reflection stuff here
return rc;
}
}
Full details can be found in the custom resolver documentation.

Resources