How to mock if condition using JUnit? - java

I am trying to mock a method using mockito. How to mock if condition using mockito?
Here is my code
#Override
public RemedyWrapperOutput createRemedyTicket(RemedyWrapperInput remedyWrapperInput) throws Exception {
logger.info("Inside createRemedyTicket");
RemedyWrapperOutput result = new RemedyWrapperOutput();
final RemedyRecord remData = remedyDao.getByApiAndTitle(remedyWrapperInput.getInstance(),
remedyWrapperInput.getTitle());
/**
* if no records exists in the DB or if the RemedyStatus is
* CLOSED/RESOLVED/CANCELLED, we create a new ticket.
*/
if (remData == null ||remData.getStatus().equals(RemedyStatus.RESOLVED)
|| remData.getStatus().equals(RemedyStatus.CLOSED)|| remData.getStatus().equals(RemedyStatus.CANCELLED)) {
createRemedyTicket(remedyWrapperInput, result);
} else {
/* If record exists check if its within duration */
/**
* If not within time range create a ticket if New and Assigned
* status. For all other status stop processing.
*/
if (!checkIfInTimeRange(remData.getCreationDateTime())) {
if (remData.getStatus() != null && (remData.getStatus().equals(RemedyStatus.NEW)
|| remData.getStatus().equals(RemedyStatus.ASSIGNED)
|| remData.getStatus().equals(RemedyStatus.PENDING)
|| remData.getStatus().equals(RemedyStatus.IN_PROGRESS))) {
int id = remedyDao.create(createRemedyInput(remedyWrapperInput, remData));
callRemedyRestApi(remedyWrapperInput, result, id);
result.setMessage("Remedy request submitted");
}
} else {
result.setMessage("A request of this category has already been logged inside specified time range.");
}
// Update the last update time to current time
remedyDao.update(remData);
}
return result;
}

I think you want to look at the method you are trying to mock. Rather than the contents of the method. Let me explain using an example. Here is a simple class that I want to test:
package com.diffblue.javademo;
public class ClassToTest {
private boolean beenChecked = false;
private SomeDAO someDAO = new SomeDAO();
public void checkActive(int id) {
if (someDAO.isActive(id)) {
beenChecked = true;
}
}
public boolean getBeenChecked() {
return beenChecked;
}
}
It makes a call to SomeDAO which I want to mock:
package com.diffblue.javademo;
public class SomeDAO {
public boolean isActive(int id) {
if (id < 5) {
return true;
}
return false;
}
}
When I am creating a test case I think about the path through checkActive that I want to test and then pick an answer from isActive that will exercise that path. For example:
package com.diffblue.javademo;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Matchers;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import static org.mockito.Mockito.when;
public class ClassToTestTest {
/**
* Test the positive side of the if statement in checkActive
*/
#PrepareForTest({SomeDAO.class})
#Test
public void positiveTest() throws Exception {
// Arrange
ClassToTest objectUnderTest = new ClassToTest();
SomeDAO someDAO = PowerMockito.mock(SomeDAO.class);
when(someDAO.isActive(Matchers.anyInt())).thenReturn(true);
int activeId = 3;
// Act
objectUnderTest.checkActive(activeId);
// Assert
Assert.assertTrue(objectUnderTest.getBeenChecked());
}
}
In this case, I have checked the path where the if statement (line 6 of SomeDAO) is true. So I haven't mocked the if statement, but I have forced a particular code path by carefully selecting the return values that Mockito is giving.

Related

Using Spock/Groovy to test a Java method that extends HashMap - how to mock HashMap get method?

In our codebase, we use a specific class map which stores the results for authorization requests including whether or not someone has the auth to get in.
Currently writing some unit tests (a thing I have little practice on) that contains this, a modified version of our code for you to look at:
public class TestResultMap extends HashMap<String, TestResult> {
private static final long serial = -1234567890L;
public boolean isAuthorized(String resource) {
TestResult result = get(resource);
if (result == null) {
throw new RunExcept("Authorization not calculated");
}
return result.isAuthorized();
}
}
When testing the isAuthorized() in the groovy file I had made, I've noticed that no matter how I have it arranged, I can not get it to instantiate TestResult result = get(resource) to be anything other than null. isAuthorized() calls upon an enum method in another class that contains the possibilities, but otherwise just returns a boolean.
That's tangential to the point, though. Is there an efficient way to mock this or force get(resource) to output something not null? Alternatively, can I directly set result to a particular value?
Thanks for any help. Incredibly new to this whole process and documentation has been tricky.
I am showing you
how to stub the result of TestResult.isAuthorized to always return true or false,
how to use a spy on a real TestResultMap instance in order to stub the result of get(_) with the rest of the class behaving normally (partial mocking),
how to test your class without using any mocks, because if the methods used in the test are not doing anything expensive, mocking might not be necessary at all. Or maybe you want to also have an integration test in addition to the unit test with mocked dependencies.
Classes under test:
package de.scrum_master.stackoverflow.q70149644;
public class TestResult {
private String result;
public TestResult(String result) {
this.result = result;
}
public boolean isAuthorized() {
return !result.toLowerCase().matches(".*(forbidden|blocked|unauthorized|denied).*");
}
#Override
public String toString() {
return "TestResult(result='" + result + "')";
}
}
package de.scrum_master.stackoverflow.q70149644;
import java.util.HashMap;
public class TestResultMap extends HashMap<String, TestResult> {
private static final long serial = -1234567890L;
public boolean isAuthorized(String resource) {
TestResult result = get(resource);
if (result == null) {
throw new RuntimeException("Authorization not calculated");
}
return result.isAuthorized();
}
}
Spock specification:
package de.scrum_master.stackoverflow.q70149644
import spock.lang.Specification
class TestResultMapTest extends Specification {
def "resource is authorized"() {
given:
TestResultMap map = new TestResultMap()
TestResult testResult = Stub() {
isAuthorized() >> true
}
map.put("resource", testResult)
expect:
map.isAuthorized("resource")
}
def "resource is unauthorized"() {
given:
TestResultMap map = new TestResultMap()
TestResult testResult = Stub() {
isAuthorized() >> false
}
map.put("resource", testResult)
expect:
!map.isAuthorized("resource")
}
def "resource not found"() {
given:
TestResultMap map = Spy() {
get(_) >> null
}
when:
map.isAuthorized("resource")
then:
def rte = thrown RuntimeException
rte.message == "Authorization not calculated"
}
def "test without mocks"() {
given:
TestResultMap map = new TestResultMap()
map.put("OK", new TestResult("Hello world"))
map.put("not OK", new TestResult("Access denied"))
expect:
map.isAuthorized("OK")
!map.isAuthorized("not OK")
when:
map.isAuthorized("foo")
then:
def rte = thrown RuntimeException
rte.message == "Authorization not calculated"
}
}

mockito mock static function does not work if the function is called in a Thread

android app, a java class needs to do something based on the NotificationManager's status.
class Util {
static void setupByPermission(#NonNull final Context appContext) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
NotificationManagerCompat nm = NotificationManagerCompat.from(appContext); // should got from stub
boolean overallPermission = currentNotificationsPermission(nm);
if (overallPermission) {
doWithPermission();
} else {
doWithoutPermission();
}
} catch (Throwable ex) {}
}
});
t.start();
}
static boolean currentNotificationsPermission(#NonNull NotificationManagerCompat nm) {
System.out.println("+++ enter currentNotificationsPermission("+nm+")");
boolean overallPermission = nm.areNotificationsEnabled();// should got result from stub
System.out.println("+++ ========= in currentNotificationsPermission("+nm+"), nm.areNotificationsEnabled() ==> "+overallPermission);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (overallPermission) {
List<NotificationChannel> channels = nm.getNotificationChannels();
boolean someChannelEnabled = channels.isEmpty();
for (NotificationChannel channel : channels) {
if (channel.getImportance() != NotificationManagerCompat.IMPORTANCE_NONE) {
someChannelEnabled = true;
break;
}
}
overallPermission = overallPermission && someChannelEnabled;
}
}
System.out.println("+++ --- exit =========== currentNotificationsPermission(), overallPermission:"+overallPermission);
return overallPermission;
}
}
would like to stub the NotificationManagerCompat.areNotificationsEnabled()
to force a test with the return of either true or false.
test using mockito-inline 3.8.0
#Test
public void test () throws Exception {
try (MockedStatic<NotificationManagerCompat> nmMoc = Mockito.mockStatic(NotificationManagerCompat.class);
MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)
) {
NotificationManagerCompat nmSpy = spy(NotificationManagerCompat.from(application));
when(nmSpy.areNotificationsEnabled())
.thenReturn(false); //or true
nmMoc.when(() -> NotificationManagerCompat.from(any(Context.class)))
.thenReturn(nmSpy);
// test
final CountDownLatch latch = new CountDownLatch(1);
utilMoc.setupByPermission(application);
latch.await(2, TimeUnit.SECONDS);
Mockito.verify(......);
}
}
but the stub is not called when they are in the Thread. same if stub the currentNotificationsPermission().
Hot to make the stub for a static function to work in the the thread?
There seem to be a few things wrong with your test:
Don't mock static methods. Refactor your code to use an interface and an implementation. This will make dependency injection easier too.
Read the Javadoc for MockedStatic. It explicitly tells you that the mock works only on the original thread.
How does your code compile? utilMoc is a MockedStatic<Util> so how can you call setupByPermission on it?
Given that you've mocked Util, calling methods on Util will not call the 'real' method anyway, unless you tell it to. See the example below.
Unit testing multithreaded code is difficult. Have a component which is responsible for executing Runnable. In your tests use a dummy implementation which runs the Runnable on the current thread.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
#ExtendWith(MockitoExtension.class)
public class TestExample {
public static class Foo {
public static String bar() {
return "bar";
}
}
#Test
public void aTest() {
try (MockedStatic<Foo> foo = Mockito.mockStatic(Foo.class)) {
// without this line Foo.bar() will return null
when(Foo.bar()).thenCallRealMethod();
assertThat(Foo.bar()).isEqualTo("bar");
}
}
}
While people have put in a lot of work to make it possible to mock static methods, as you're seeing it still isn't straightforward. The refactoring needed to avoid it is straightforward and has other benefits.

Testing class that insert, update and delete from the db

I have class that has 3 methods: insert, update and delete from the db.
In order to test it in the insert test method I need to use the insert method and after I insert i need to delete what I inserted, but in order to delete I should use the delete method that I also want to test so it didn't make sense to me that I need to use them and also test them.
I hope you understand my problem. Thanks in advance!
You must decide what you want to test. That was you describe, it is an integration test. By a “real” unitTest, you test only your method, and not the System method and not the database.
If you want a unitTest, you have several options. For Example, you work with interfaces and catch your statement before it comes to the database.
Edit 1 - one possibility to implement unit test with interfaces:
You need one interface that implements the method these go to the backend system:
public interface IDatabase{
public returnValue insert(yourParam);
public int update(yourParam);
}
Then you implement your method with the real functions in a class:
public class Database implements IDatabase {
#Override
public returnValue insert(yourParam) {
// do something
return null;
}
#Override
public int update(yourParam){
// do something
return 0;
}
}
This class you call in the main class:
/**
* The real class to do what you want to do.
*/
public class RealClass {
private IDatabase dbInstance = null;
private IDatabase getDbInstance() {
if (dbInstance == null) {
dbInstance = new Database();
}
return dbInstance;
}
protected void setDbInstance(IDatabase dataBase) {
dbInstance = dataBase;
}
public static void main(String[] args) {
getDbInstance().insert(yourParam);
}
}
For the unit test you implement the interface again:
public class UnitTest implements IDatabase {
#Override
public returnValue insert(yourParam) {
// Here can you test your statement and manipulate the return value
return null;
}
#Override
public int update(yourParam){
if (yourParam.containsValue(value1)) {
assertEquals("yourStatement", yourParam);
return 1;
}else if (yourParam.containsValue(value2)) {
assertEquals("yourStatement2", yourParam);
return 5;
}else{
assertTrue(false,"unknown Statement")
}
}
#Test
public void yourTest(){
RealClass.setDbInstance(this);
//Test something
}
}
This is time-consuming to implement, but with this, you are independent from the backend system and you can call the unittest every time without a database.
By default, the order of test methods is not warrantied in JUnit. Nevertheless, as of JUnit 4.11, you can order by the test name, as follows:
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Test1 {
#Test
public void aInsert() {
System.out.println("first INSERT");
}
#Test
public void bUpdate() throws Exception {
System.out.println("second UPDATE");
}
#Test
public void cDelete() throws Exception {
System.out.println("third DELETE");
}
}

Stub void method in Spock which populate

How can I stub/mock a void method which populates some objects that would be used later.
class RequestHelper{
public void populateOrderRequestBody(String product,String quantity,String profile, OrderType orderType){
orderType.setProduct(product);
orderType.setQuantity(Integer.parseInt(quantity));
orderType.setUser(profile.getUserId());
} }
class ServiceClient{
RequestHelper rh;
public void docall(Order order){
OrderType orderType = FACTORY.CreateOrderType;
rh.populateOrderRequestBody(order.getProduct(),order.getQuantity(),order.getProfile(),orderType);
/**
* some other code
**/
}
public setRequestHelper(RequestHelper rh){
this.rh=rh;
}
public RequestHelper getRequestHelper(){
return this.rh;
}}
Now I want to test ServiceClient class which call RequestHelper to populate orderType object. How to stub the method of RequestHelper class.
In this particular case if no verification will be done to rh filed you just need a plain Stub - just to ensure no NullPointerException is thrown when testing the docall method. Mock will also be sufficient however is more advanced object and using it here is pointless. When it comes to Spy it's used to verify invocations on a real (in terms of not being mocked) object. Have a look at the example below - runs smoothly just with Stub:
#Grab('org.spockframework:spock-core:1.0-groovy-2.4')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
def 'spec'() {
given:
def service = new ServiceClient()
service.rh = Mock(RequestHelper)
when:
service.doCall(new Order())
then:
noExceptionThrown()
}
}
class Order {
String product
String quantity
String profile
}
class OrderType { }
class FACTORY {
static OrderType CreateOrderType = new OrderType()
}
class RequestHelper {
public void populateOrderRequestBody(String product, String quantity, String profile, OrderType orderType) {
orderType.setProduct(product);
orderType.setQuantity(Integer.parseInt(quantity));
orderType.setUser(profile.getUserId());
}
}
class ServiceClient {
RequestHelper rh;
public void doCall(Order order) {
OrderType orderType = FACTORY.CreateOrderType;
rh.populateOrderRequestBody(order.getProduct(), order.getQuantity(), order.getProfile(), orderType);
}
public setRequestHelper(RequestHelper rh){
this.rh=rh;
}
public RequestHelper getRequestHelper(){
return this.rh;
}
}
Very similar to Opal's answer but using a mock order..
class Test extends Specification {
def 'spec'() {
given:
def service = new ServiceClient()
def order = Mock(Order)
order.getProduct() >> 'product1'
order.getProfile() >> 'profile1'
order.getQuantity() >> 3
service.rh = Mock(RequestHelper)
when:
service.doCall(order)
then:
noExceptionThrown()
1 * rh.populateOrderRequestBody('product1',3,'profile1',FACTORY.CreateOrderType)
}
}
Note that this only works if the CreateOrderType.equals() will return true

BeanUtils not works for chain setter

e.g.
class tester
{
#Test
public void testBeanUtils() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
{
Stranger stranger = new Stranger();
BeanUtils.setProperty(stranger,"name","wener");
BeanUtils.setProperty(stranger,"xname","xwener");
BeanUtils.setProperty(stranger,"yname","ywener");
System.out.println(stranger);
}
#Data// lombok annotation generate all setter and getter
public static class Stranger
{
#Accessors(chain = true)// generate chained setter
String name;
String xname;
String yname;
public Stranger setYname(String yname)// no lombok, still not work
{
this.yname = yname;
return this;
}
}
}
My output:
TestValues.Stranger(name=null, xname=xwener, yname=null)
What's wrong with this? chain setter is a good thing.
Any suggests ?
EDIT
Back to this problem again.This time I can not remove the Accessors chain.
Now, I use the commons-lang3 to achieve.
// force access = true is required
Field field = FieldUtils.getField(bean.getClass(), attrName, true);
field.set(bean,value);
For those who got the same problem.
You can use the FluentPropertyBeanIntrospector implementation:
"An implementation of the BeanIntrospector interface which can detect write methods for properties used in fluent API scenario."
https://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/FluentPropertyBeanIntrospector.html
PropertyUtils.addBeanIntrospector(new FluentPropertyBeanIntrospector());
BeanUtils.setProperty( this.o, "property", "value" );
That's simple: BeanUtils are rather strange and so is Introspector it uses:
Although BeanUtils.setProperty declares some exceptions, it seems to silently ignore the non-existence of the property to be set. The ultimate culprit is the Introspector which simply requires the voidness of setter.
I'd call it broken by design, but YMMV. It's an old class and fluent interfaces weren't invented yet in those dark times. Use Accessors(chain=false) to disable chaining.
More important: Use the source. Get it and get a debugger (it's already in your IDE) to find it out yourself (still feel free to ask if it doesn't work, just try a bit harder).
In my project we use chained accessors across the board, so setting chain=false was not an option. I ended up writing my own introspector, which is similar to the one recommended by #mthielcke, and may be registered in the same way.
Introspector
import org.apache.commons.beanutils.BeanIntrospector;
import org.apache.commons.beanutils.IntrospectionContext;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
/**
* Allows {#link org.apache.commons.beanutils.BeanUtils#copyProperties(Object, Object)} to copy properties across beans whose
* properties have been made <b>fluent</b> through Lombok
* {#link lombok.experimental.Accessors}, {#link lombok.Setter} and {#link lombok.Getter} annotations.
*
* #author izilotti
*/
#Slf4j
public class LombokPropertyBeanIntrospector implements BeanIntrospector {
/**
* Performs introspection. This method scans the current class's methods for property write and read methods which have been
* created by the Lombok annotations.
*
* #param context The introspection context.
*/
#Override
public void introspect(final IntrospectionContext context) {
getLombokMethods(context).forEach((propertyName, methods) -> {
if (methods[0] != null && methods[1] != null) {
final PropertyDescriptor pd = context.getPropertyDescriptor(propertyName);
try {
if (pd == null) {
PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, methods[1], methods[0]);
context.addPropertyDescriptor(descriptor);
}
} catch (final IntrospectionException e) {
log.error("Error creating PropertyDescriptor for {}. Ignoring this property.", propertyName, e);
}
}
});
}
private Map<String, Method[]> getLombokMethods(IntrospectionContext context) {
Map<String, Method[]> lombokPropertyMethods = new HashMap<>(); // property name, write, read
Stream.of(context.getTargetClass().getMethods())
.filter(this::isNotJavaBeanMethod)
.forEach(method -> {
if (method.getReturnType().isAssignableFrom(context.getTargetClass()) && method.getParameterCount() == 1) {
log.debug("Found mutator {} with parameter {}", method.getName(), method.getParameters()[0].getName());
final String propertyName = propertyName(method);
addWriteMethod(lombokPropertyMethods, propertyName, method);
} else if (!method.getReturnType().equals(Void.TYPE) && method.getParameterCount() == 0) {
log.debug("Found accessor {} with no parameter", method.getName());
final String propertyName = propertyName(method);
addReadMethod(lombokPropertyMethods, propertyName, method);
}
});
return lombokPropertyMethods;
}
private void addReadMethod(Map<String, Method[]> lombokPropertyMethods, String propertyName, Method readMethod) {
if (!lombokPropertyMethods.containsKey(propertyName)) {
Method[] writeAndRead = new Method[2];
lombokPropertyMethods.put(propertyName, writeAndRead);
}
lombokPropertyMethods.get(propertyName)[1] = readMethod;
}
private void addWriteMethod(Map<String, Method[]> lombokPropertyMethods, String propertyName, Method writeMethod) {
if (!lombokPropertyMethods.containsKey(propertyName)) {
Method[] writeAndRead = new Method[2];
lombokPropertyMethods.put(propertyName, writeAndRead);
}
lombokPropertyMethods.get(propertyName)[0] = writeMethod;
}
private String propertyName(final Method method) {
final String methodName = method.getName();
return (methodName.length() > 1) ? Introspector.decapitalize(methodName) : methodName.toLowerCase(Locale.ENGLISH);
}
private boolean isNotJavaBeanMethod(Method method) {
return !isGetter(method) || isSetter(method);
}
private boolean isGetter(Method method) {
if (Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0) {
if (method.getName().matches("^get[A-Z].*") && !method.getReturnType().equals(Void.TYPE)) {
return true;
}
return method.getName().matches("^is[A-Z].*") && method.getReturnType().equals(Boolean.TYPE);
}
return false;
}
private boolean isSetter(Method method) {
return Modifier.isPublic(method.getModifiers())
&& method.getReturnType().equals(Void.TYPE)
&& method.getParameterTypes().length == 1
&& method.getName().matches("^set[A-Z].*");
}
}
Registration
PropertyUtils.addBeanIntrospector(new LombokPropertyBeanIntrospector());
BeanUtils.copyProperties(dest, origin);

Categories

Resources