I have a class for which i am writing groovy test case. This class has constructor autowiring and calls another method to initialise the fields.:
#Service
public class ServiceA {
private final PrincipalDao principalDao;
#Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao=principalDao;
this.serviceMap = getMap();
}
private Map<> getMap() {
final List<ClassA> classAList = principalDao.findAll(); //this line returns null
}
}
this line final List<ClassA> classAList = principalDao.findAll(); returns null and I cant mock it in groovy like following:
principalDao.findAll() >> list
because its called even before my above line is called in groovy test case
Without seeing you unit test, it's hard to tell what the issue is, but a common misconception I run into sometimes is the timing of the mock.
Here's a sample code elaborating what I mean. Since parts of the code missing from your question, going to assume some parts of it, but I'm sure it explains the point I'm making and hopefully should help you out in finding an answer:
Service class:
#Service
public class ServiceA{
private final PrincipalDao principalDao;
private final Map<String, String> serviceMap;
#Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao = principalDao;
this.serviceMap = getMap();
}
private Map<String, String> getMap(){
final HashMap<String, String> stringStringHashMap = new HashMap<String, String>();
stringStringHashMap.put("hello", principalDao.khello());
return stringStringHashMap;
}
public String printServiceMap() {
return serviceMap.get("hello");
}
}
class ServiceATest extends Specification {
def "some test"() {
given:
PrincipalDao principalDao = Mock()
principalDao.khello() >> "khello" // this is the key here. Mocking is happening before instantiation of ServiceA
ServiceA someService = new ServiceA(principalDao)
expect:
"khello" == someService.printServiceMap()
}
}
This unit test passes successfully. The point here is the timing of the mocking. principalDao.khello() >> "khello" happens before new ServiceA(principalDao).
If you don't need to modify serviceMap per unit test, you can also do this so you don't have to define it per unit test:
class ServiceATest extends Specification {
#Shared
PrincipalDao principalDao = Mock()
ServiceA someService = new ServiceA(principalDao)
def setupSpec() {
principalDao.khello() >> "khello"
}
def "some test"() {
expect:
"khello" == someService.printServiceMap()
}
}
Related
I cant seem to successfully run the test case successfully.
i have and implementation class which calls a private method as follows:
#Service
public class PermissionServiceImpl implements PermissionService {
#Autowired
private PermissionRepository permissionRepository;
#Autowired
private UserRoleRepository roleRepository;
#Override
public Set<PermissionType> getPermissions(String accessToken, String clientId) {
Map<String, List<String>> userRoles = getUserRoles(accessToken);
List<UserRole> currRole = getCurrRole(userRoles, clientId);
return getCurrentPermissions(currRole);
}
private Map<String, List<String>> getUserRoles(String accessToken) {
Map<String, List<String>> roles = new HashMap<>();
UserAccessTokenInfo userAccessTokenInfo =
SessionValidatorWithOKTA.getTokenMap().get(accessToken);
if (userAccessTokenInfo != null) {
roles = userAccessTokenInfo.getRoles();
}
return roles;
}
The above code is just a snippet. Havent given the full class due to confidentiality clause.
I have the following test case written:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PermissionServiceImpl.class)
#ExtendWith(MockitoExtension.class)
public class PermissionServiceImplTest {
#InjectMocks
PermissionService permissionService = new PermissionServiceImpl();
#Mock
PermissionRepository permissionRepository;
#Mock
UserRoleRepository roleRepository;
#Test
public void testGetPermissions() {
Set<PermissionType> permissionTypes = permissionService.getPermissions(ConstantsMock.ACCESS_TOKEN, ConstantsMock.CLIENT_ID);
assertEquals(permissionTypes, new HashSet<>());
}
#Test
public void testGetPermissions_withRoles() throws Exception {
Map<String, List<String>> roles = new HashMap();
roles.put(ConstantsMock.CLIENT_ID, new ArrayList<>(Arrays.asList("admin")));
PermissionServiceImpl mocked = PowerMockito.spy(new PermissionServiceImpl());
PowerMockito.when(mocked, method(PermissionServiceImpl.class, "getUserRoles", String.class))
.withArguments(anyString())
.thenReturn(roles);
mocked.getPermissions(ConstantsMock.ACCESS_TOKEN, ConstantsMock.CLIENT_ID)
}
}
I am getting the following error:
Misplaced or misused argument matcher detected here:
-> at
PermissionServiceImplTest.testGetPermissions_withRoles(PermissionServiceImplTest.java:51)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matches:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an
object like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be
mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
Can provide further details if needed.
#Autowired
private Publisher Publisher;
private int Id = 12345;
private BClient bClient = new BClient(Id);
private Map<Integer, Boolean> defaultBooleanValueMap;
private LoadCache<Integer, Boolean> booleanCache = CacheBuilder.newBuilder()
.refreshAfterWrite(refreshRate, TimeUnit.SECONDS)
.build(
new CacheLoader<Integer, Boolean>() {
#Override
public Boolean load(Integer id) throws Exception {
return fetchBooleanValue(id);
}
}
);
private boolean fetchBooleanValue(int id) {
long fetchStart = System.currentTimeMillis();
boolean val = bClient.getBoolean(id, defaultBooleanValueMap.get(id));
publisher.publish(
publisher.getDistributionMetric("fetchtime.bool", System.currentTimeMillis() - fetchStart));
return val;
}
public boolean getBoolean(int id) {
return booleanCache.getUnchecked(id);
}
//Trying to test getBoolean(int id) function. I'm mocking bClient, Publisher. Not sure how to properly test it
// Could anyone help me understand how to test it
//testing with
SomeClass someClass = new SomeClass();
#Mock
Publisher publisher;
#Mock
BClient bClient;
#Test
public void testGetBoolean(){
bClient = new BClient(12345);
Map<Integer,Boolean> defaultBooleanValueMap = null;
defaultBooleanValueMap.put(123, false);
when(bClient.getBoolean(123,
defaultBooleanBregValueMap.get(123))).thenReturn(false);
boolean b = someClass.getBoolean(123);
assertFalse(b);
}
// i'm don't know if i'm doing it right
Are you using Mockito?
It's good practice to not start a field name with a capital (Publisher for instance)
Personally i think it will be better to make all these methods protected instead of private, so that you can test each of them separately.
however this would be an example of a unit test for your code.
You can use Mockito to check if certain method calls are fired the amount of time you expect them to be fired.
I did not include all but you can just add if you need more tests.
Further i recommend to read about Mockito as it has some really powerful unit test tools
#Test
public void testGetBoolean () {
xxx.getBoolean
//the following line can only be done if you spy your service
Mockito.verify(xxx, times(1)).fetchBooleanValue(any());
//this line can be done if you mock bClient
Mockito.verify(bClient , times(1)).getBoolean(any(), any()); //Mockito.any() or you can fill in the real values if you really want.
//this line can be done if you mock Publisher
Mockito.verify(publisher, times(1)).publish(any); //again any or the real value you want to pass
}
I just now saw your unit tests, you can inject the mocks in you class with the following anotatation:
#InjectMocks
SomeClass someClass;
when mocking a class you don't manually have to create it again.
You don't have to mock the Bclient as you already create it with "new Bclient" instead of autowiring it.
I feel the #InjectMocks is not working because you didn't tell Spring that your class is a service component.
#Service
public class SomeClass {
//insert code here
}
In application code when dealing with forms it is recommended to use a FormFactory to create a Form wrapper around the form of type T. But when it comes to testing, what is the way to create a Form? (Do you have to inject FormFactory in the test?)
My app does something similar to that:
class MyAmazingClass {
private final FormFactory formFactory;
#Inject
MyAmazingClass(FormFactory formFactory) {
this.formFactory = formFactory;
}
public CompletionStage<Result> myAmazingMethodHandlingForms() {
Form<String> form = formFactory.form(String.class).bindFromRequest();
// ... Actually doing something
return null;
}
}
What shall my test class (for unit testing) looks like?
I am trying something like this but I think I should not try to inject the FormFactory (also it does not seems to work):
public class MyAmazingClassTest extends WithApplication {
#Mock
FormFactory mockedFormFactory;
#Inject
FormFactory realFormFactory;
MyAmazingClass myAmazingClass;
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().build();
}
#Before
public void setUp() throws Exception {
myAmazingClass = new MyAmazingClass(mockedFormFactory);
}
#Test
public void testMyAmazingMethodHandlingForms() throws Exception {
String myString = "ciao";
Form<String> stringForm = realFormFactory.form(String.class).fill(myString);
when(mockedFormFactory.form(eq(String.class)).bindFromRequest()).thenReturn(stringForm);
myAmazingClass.myAmazingMethodHandlingForms();
// Some assertions...
}
}
I am using JUnit 4, Java 8 and Play framework 2.5.
I would say that mixing mocks with the real application is not the best idea here. You should either use mocks (and avoid WithApplication), or you can use the "real" instances by calling app.injector().instanceOf() (including for your MyAmazingClass). For example, when only using mocks:
public class MyAmazingClassTest {
#Test
public void testMyAmazingMethodHandlingForms() throws Exception {
Form<String> form = mock(Form.class);
// setup the mocked form as you expect it to behave
FormFactory formFactory = mock(FormFactory.class);
when(formFactory.form(eq(String.class)).bindFromRequest()).thenReturn(form);
MyAmazingClass myAmazingClass = new MyAmazingClass(formFactory);
myAmazingClass.myAmazingMethodHandlingForms();
// Some assertions...
}
}
Testing using the real instances would requires you to do a request, since apparently, you are binding from the request:
public class MyAmazingClassTest extends WithApplication {
#Test
public void testMyAmazingMethodHandlingForms() throws Exception {
Map<String, String> formData = new HashMap<>();
formData.put("some", "value");
// fill the form with the test data
Http.RequestBuilder fakeRequest = Helpers.fakeRequest().bodyForm(formData).method(Helpers.POST);
Result result = Helpers.route(app, fakeRequest);
// make assertions over the result or something else.
}
}
I'm having difficulties trying to mock a dependency within Guava Collection.
Let's assume I have a following code to test:
#Service
public final class ServiceA {
private final ServiceB serviceB;
#Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public Collection<String> runAll(Collection<String> dataList) {
final ImmutableList.Builder<String> builder = ImmutableList.builder();
for (String data : dataList) {
builder.add(serviceB.run(data));
}
return builder.build();
}
}
My Spock Spec looks like this:
class ServiceASpec extends Specification {
def serviceB = Mock(ServiceB.class)
def serviceA = new ServiceA(serviceB)
def "test"() {
when:
def strings = serviceA.runAll(['data1', 'data2'])
then:
1 * serviceB.run('data1') >> 'result1'
1 * serviceB.run('data2') >> 'result2'
0 * _._
strings == ['result1', 'result2']
}
}
This spec runs just fine and it is doing what I want it to do.
Then I refactored my implementation to use Guava's Collections2.transform(..):-
#Service
public final class ServiceA {
private final ServiceB serviceB;
#Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public Collection<String> runAll(Collection<String> dataList) {
return Collections2.transform(dataList, new Function<String, String>() {
#Override
public String apply(final String input) {
return serviceB.run(input);
}
});
}
}
When I rerun my spec, I'm getting this error:-
Too few invocations for:
1 * serviceB.run('data1') >> 'result1' (0 invocations)
Unmatched invocations (ordered by similarity):
None
Too few invocations for:
1 * serviceB.run('data2') >> 'result2' (0 invocations)
Unmatched invocations (ordered by similarity):
None
My take is it has something to do with the mocking timing because the Guava function will only be executed when the collection is used.
However, I wasn't sure how to refactor my spec to make this to work.
How do I go about solving this? Thanks.
Under the hood transform() method returns TransformedCollection class. As you can see here transformation is applied no sooner than on iterating the wrapped collection. Since you don't iterate the transformed collection mocked service is not invoked and no interaction is recorded.
It seems that simply iterating the collection should solve the problem, however such test should be really well documented.
Another way is using FluentIterable.from(list).transform(function).toList() instead of Collections2.transform(list, function).
In my controller I have code like the following.
RedisTemplate stringRedisTemplate
def accessRedis()
{
val = stringRedisTemplate.opsForValue().get('Key')
}
In my controller Test, I intent to inject a mocked RedisTemplate that return a mocked ValueOperations. My code:
def template = mockFor(RedisTemplate)
def val = mockFor(org.springframework.data.redis.core.ValueOperations)
val.demand.get {p-> println "$p"}
template.demand.opsForValue {
return val.createMock()
}
controller.stringRedisTemplate = template.createMock()
controller.accessRedis()
However, I got the following error:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'com.tnd.viewport.ui.AppHawkControllerSpec$_$spock_feature_0_1_closure2#1aa55dd5' with class 'com.tnd.viewport.ui.AppHawkControllerSpec$_$spock_feature_0_1_closure2' to class 'org.springframework.data.redis.core.ValueOperations'
Could you advice a solution for my scenario? Thanks!
It's simple. Mock them separately.
Eg.
#MockBean
private RedisTemplate<String, String> redisTemplate;
#MockBean
private ValueOperations valueOperations;
#Test
public void testRedisGetKey() {
// This will make sure the actual method opsForValue is not called and mocked valueOperations is returned
doReturn(valueOperations).when(redisTemplate).opsForValue();
// This will make sure the actual method get is not called and mocked value is returned
doReturn("someRedisValue").when(valueOperations).get(anyString());
}
redisTemplate = mock(RedisTemplate.class);
Whitebox.setInternalState(loginService, "redisTemplate", redisTemplate);
List<Object> list = new ArrayList<Object>();
list.add(15l);
List<Object> keys = new ArrayList<>();
keys.addAll(Arrays.asList("15"));
HashOperations<Serializable, Object, Object> hashOperations =mock(HashOperations.class);
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
when(hashOperations.multiGet(anyString(), anyListOf(Object.class))).thenReturn(list);