Powermockito for nested abstract class - amazon-web-services

I am not able do proper mock one of the AWS translation client due to expending nested abstract class:
Java class
import com.amazonaws.services.comprehend.AmazonComprehend;
import com.amazonaws.services.translate.AmazonTranslate;
public class TestLambdaFunctionHandler implements RequestHandler<InputPayLoadPojo, Response> {
AmazonTranslate awsTranslateClient = null;
AmazonComprehend comprehendClient = null;
awsTranslateClient = AmazonTranslateClientBuilder.standard().build();
comprehendClient = AmazonComprehendClientBuilder.standard().build();
........
}
Junit test class
import com.amazonaws.services.comprehend.AmazonComprehend;
import com.amazonaws.services.translate.AmazonTranslate;
import com.amazonaws.services.comprehend.AmazonComprehendClientBuilder;
import com.amazonaws.services.translate.AmazonTranslateClientBuilder;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
import junit.framework.TestCase;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static com.google.common.util.concurrent.Runnables.doNothing;
import static org.powermock.api.mockito.PowerMockito.whenNew;
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({ "javax.net.ssl.*" })
#PrepareForTest({AmazonComprehendClientBuilder.class, AmazonComprehendClientBuilder , AmazonTranslate.class, AmazonComprehend.class,})
public class SynchronousTest {
#Before
public void setup() {
}
#Test
public void testSynchronousTranslation() {
TaaSSyncLambdaFunctionHandler obj = Mockito.spy(new TaaSSyncLambdaFunctionHandler());
AmazonTranslate awsTransMock = PowerMockito.mock(AmazonTranslate.class);
AmazonComprehend awsComprehendMock = PowerMockito.mock(AmazonComprehend.class);
AmazonTranslateClientBuilder awsTranslateClientBuilderMock = PowerMockito.mock(AmazonTranslateClientBuilder.class);
AmazonComprehendClientBuilder awsComprehendClientBuilderMock = PowerMockito.mock(AmazonComprehendClientBuilder.class);
when(awsTranslateClientBuilderMock.standard().build()).thenReturn(awsTransMock);
when(awsComprehendClientBuilderMock.standard().build()).thenReturn(awsComprehendMock);
...................
}
}
error:
com.amazonaws.SdkClientException: Unable to find a region via the region provider chain. Must provide an explicit region in the builder or setup environment to supply a region.
at com.amazonaws.client.builder.AwsClientBuilder.setRegion(AwsClientBuilder.java:386)
at com.amazonaws.client.builder.AwsClientBuilder.configureMutableProperties(AwsClientBuilder.java:352)
at com.amazonaws.client.builder.AwsSyncClientBuilder.build(AwsSyncClientBuilder.java:46)
at taas.amazonservices.lambda.SynchronousTest.testSynchronousTranslation(SynchronousTest.java:89)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
After investigation found that AmazonTranslateClientBuilder extends abstract classs AwsSyncClientBuilder
and AwsSyncClientBuilder extends abstract class.
This is found below.
public final class AmazonTranslateClientBuilder extends AwsSyncClientBuilder<AmazonTranslateClientBuilder, AmazonTranslate> {
public abstract class AwsSyncClientBuilder<Subclass extends AwsSyncClientBuilder, TypeToBuild> extends AwsClientBuilder<Subclass, TypeToBuild> {
even after adding below mock for abstract class, still getting same error:
AwsSyncClientBuilder cut= Mockito.mock(AwsSyncClientBuilder.class,Mockito.CALLS_REAL_METHODS);
AwsClientBuilder cut1= Mockito.mock(AwsClientBuilder.class,Mockito.CALLS_REAL_METHODS);
Please provide any technical to resove these type of class.
Thanks,
Ranjit Kumar

Related

How powermockit mocks a private method

Here, I want to understand the internals of Powermockito. How does it mock a private method?
I thought that it uses a new class loader to create a different copy of the class, but when I tried to do the same, I got a runtime exception showing that the 2 classes (one originally created by System class loader) and the one I passed are of different versions.
package com.concretepage.lang;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
public class MainClass {
public static void main(String[] args) throws InstantiationException, IllegalAccessException,
NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, MalformedURLException {
CustomClassLoaderDemo loader = new CustomClassLoaderDemo();
Class<?> c = loader.findClass("com.concretepage.lang.Test");
Object ob = c.newInstance();
Method md = c.getMethod("show");
md.invoke(ob);
System.out.println(c.getClassLoader());
System.out.println(ob.getClass().getClassLoader());
((com.concretepage.lang.Test)ob).show();
Test c2 = new Test();
System.out.println(c2.getClass().getClassLoader());
Class<?> cClass = Class.forName("com.concretepage.lang.Test");
System.out.println(cClass.getClassLoader());
java.net.URLClassLoader urlLoader = java.net.URLClassLoader.newInstance(new URL[] {new URL("File://c//Users//dell//eclipse-workspace//DeemTest//src")}, loader);
Class<?> testRemoteClazz = urlLoader.loadClass("com.concretepage.lang.Test");
Object obUrl = testRemoteClazz.newInstance();
Method mdUrl = testRemoteClazz.getMethod("show");
mdUrl.invoke(obUrl);
}
}
If your unit test is une the same package path, you may try to pass your methods in protected.
Example :
app package => myapp.services.impl
test package => myapp.serviceS.impl
Then with the same package name, the method protected will be reachable for the test.
If you can't make that, you should pass the method to public, but i don't think that's your objective... Proceted is in general a good solution.

Spock unit testing assert log calls and see output

I am using spock to test Java Spring Boot code. It gets a logback logger over the lombok #Slf4j annotation.
Dummy class with log call
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
#Slf4j
#Component
public class Clazz {
public void method() {
// ... code
log.warn("message", new RuntimeException());
}
}
The Spock Spec
import groovy.util.logging.Slf4j
import org.junit.Rule
import org.slf4j.Logger
import spock.lang.Specification
#Slf4j
class LogSpec extends Specification {
Clazz clazz = new Clazz()
private Logger logger = Mock(Logger.class)
#Rule
ReplaceSlf4jLogger replaceSlf4jLogger = new ReplaceSlf4jLogger(Clazz, logger)
def "warning ia logged"() {
given: "expected message"
when: "when calling the method"
clazz.method()
then: "a warning is logged"
1 * logger.warn(_, _) >> {
msg, ex -> log.warn(msg, ex)
}
}
}
Helper to switch the real with the mock logger taken from this answer.
import org.junit.rules.ExternalResource
import org.slf4j.Logger
import java.lang.reflect.Field
import java.lang.reflect.Modifier
/**
* Helper to exchange loggers set by lombok with mock logger
*
* allows to assert log action.
*
* Undos change after test to keep normal logging in other tests.
*
* code from this answer answer
*/
class ReplaceSlf4jLogger extends ExternalResource {
Field logField
Logger logger
Logger originalLogger
ReplaceSlf4jLogger(Class logClass, Logger logger) {
logField = logClass.getDeclaredField("log")
this.logger = logger
}
#Override
protected void before() throws Throwable {
logField.accessible = true
Field modifiersField = Field.getDeclaredField("modifiers")
modifiersField.accessible = true
modifiersField.setInt(logField, logField.getModifiers() & ~Modifier.FINAL)
originalLogger = (Logger) logField.get(null)
logField.set(null, logger)
}
#Override
protected void after() {
logField.set(null, originalLogger)
}
}
I would like to test log calls, but still see the log message.
I am using the solution from this answer, it works for the assertion but I don't see the log because it is a mock call.
I came up with this solution, which does a the call with the logger of the groovy spec.
1 * logger.warn(_ , _) >> {
msg, ex -> log.warn(msg, ex)
}
But I find it verbose, any idea how I could create a helper function for it. I am not very familiar with functional groovy and moving this code into a function is not working.
I also tried a Spy instead of a Mock but that gets me an error because the logger class is final.
import ch.qos.logback.classic.Logger
private Logger logger = Spy(Logger.class)
>> org.spockframework.mock.CannotCreateMockException: Cannot create mock
for class ch.qos.logback.classic.Logger because Java mocks cannot mock final classes.
If the code under test is written in Groovy, use a Groovy mock.
Logger class at runtime
package ch.qos.logback.classic;
public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {
Thanks
Actually in your MCVE you expect the warn(_, _) method to be called with two parameters, but you are not logging like that in Clazz, so either you have to change Clazz to also log an exception or change the test to expect a method call with one parameter. I am doing the latter here.
As for your problem, the solution is to not use a mock but a spy. You need to tell Spock which exact class you want to spy on, though. This is because you cannot spy on an interface type, of course. I have chosen a SimpleLogger (change to whatever you use in your application).
package de.scrum_master.stackoverflow
import groovy.util.logging.Slf4j
import org.junit.Rule
import org.slf4j.impl.SimpleLogger
import spock.lang.Specification
#Slf4j
class LombokSlf4jLogTest extends Specification {
SimpleLogger logger = Spy(constructorArgs: ["LombokSlf4jLogTest"])
#Rule
ReplaceSlf4jLogger replaceSlf4jLogger = new ReplaceSlf4jLogger(Clazz, logger)
def "warning is logged"() {
when: "when calling the method"
new Clazz().method()
then: "a warning is logged"
1 * logger.warn(_)
}
}
Update: For what it is worth, here is a version which also works with LogBack-Classic instead of Log4J-Simple on the classpath. Instead of directly spying on the final class, let's just spy on a Groovy #Delegate:
Please also note that I changed to *_ in the test so as to accommodate to warn calls with an arbitrary number of arguments.
package de.scrum_master.stackoverflow
import groovy.util.logging.Slf4j
import org.junit.Rule
import org.slf4j.Logger
import spock.lang.Specification
#Slf4j
class LombokSlf4jLogTest extends Specification {
def logger = Spy(new LoggerDelegate(originalLogger: log))
#Rule
ReplaceSlf4jLogger replaceSlf4jLogger = new ReplaceSlf4jLogger(Clazz, logger)
def "warning is logged"() {
when: "when calling the method"
new Clazz().method()
then: "a warning is logged"
1 * logger.warn(*_)
true
}
static class LoggerDelegate {
#Delegate Logger originalLogger
}
}
Update 2020-01-23: I just found this one again and noticed that I forgot to explain why the #Delegate solution works: because a Groovy delegate automatically implements all interfaces which the class of the delegate instance also implements by default. In this case the logger field is declared as Logger which is an interface type. This is also why e.g. Log4J or Logback instances can be used based on the configuration. The trick of mocking or spying on a final class type not implementing an interface or used explicitly with its class name would not work in that case because the delegating class would not (and could not) be a subclass of the final class type and thus could not be injected instead of the delegate.
Update 2020-04-14: I did not mention before that if you don't want to spy on a real logger but simply use a dummy you can check interactions on, just use a regular Spock mock on the org.slf4j.Logger interface: def logger = Mock(Logger) That is actually the simplest solution and you don't clutter your test log with exception stack traces and other log output. I was so focused on helping the OP with his spy solution that I did not mention this before.
These is one more "creative" approach for this kind of issue I would like to share.
Instead of mocking the logger you can create an "artificial" appender, add it programmatically to the logger in the class under-test.
The appender will keep track of the logged messages and during the verification phase you will get those logged message and verify
You'll end up with something like this (pseudo code just to show the idea):
class MsgTrackingAppender implements Appender { // Appender of your logging system
private List<LogEvent> events = new ArrayList<>();
public void doAppend(LogEvent evt) {
events.add(evt);
}
public List<LogEvent> getEvents() {
return events;
}
}
// now in test you can do:
class LogSpec extends Specification {
def "test me"() {
given:
Clazz underTest = Clazz()
MsgTrackingAppender appender = new MsgTrackingAppender()
LogFactory.getLogger(Clazz.class).addAppender(appender)
when:
underTest.method()
then:
appender.events.size == 1
appender.events[0].level == Level.WARN
appender.events[0].message == ... // verify whatever you want on the messages
}
}
IMO this approach is easier to use than extensive mocking but its a matter of taste of course.

Unable to Mock behavior using Mockito for testing Struts2 action class method

Well this is the setup that I have:
WelcomeUser.java
package org.user.www.action;
import org.user.www.dao.ApplicationDAOfactory;
import org.user.www.dao.UserPojoDao;
import org.user.www.pojo.UserPojo;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class WelcomeUser extends ActionSupport implements ModelDriven<UserPojo> {
private static final long serialVersionUID = 1L;
private UserPojo userPojo = new UserPojo();
private ApplicationDAOfactory appFactory = new ApplicationDAOfactory();
private UserPojoDao appDAOObj /*= ApplicationDAOfactory.getUserPojoDaoInstance()*/;
public WelcomeUser(){
}
public WelcomeUser(UserPojoDao appDAOObj, ApplicationDAOfactory appFactory){
this.appDAOObj = appDAOObj;
this.appFactory = appFactory;
}
public String execute(){
return SUCCESS;
}
#Override
public UserPojo getModel() {
// TODO Auto-generated method stub
return userPojo;
}
public String welcome(){
appDAOObj = appFactory.getUserPojoDaoInstance();
appDAOObj.persistUser(userPojo);
return SUCCESS;
}
}
ApplicationDAOfactory.java
package org.user.www.dao;
public class ApplicationDAOfactory {
public UserPojoDao getUserPojoDaoInstance(){
return new UserPojoDaoImpl();
}
}
WelcomeUserTest.java
package org.user.www.junit;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import org.apache.struts2.StrutsJUnit4TestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.user.www.action.WelcomeUser;
import org.user.www.dao.ApplicationDAOfactory;
import org.user.www.dao.UserPojoDao;
import org.user.www.dao.UserPojoDaoImpl;
import org.user.www.pojo.UserPojo;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
#RunWith(MockitoJUnitRunner.class)
public class WelcomeUserTest extends StrutsJUnit4TestCase<WelcomeUser>{
#Mock private UserPojoDao appDAOObj;
#Mock private ApplicationDAOfactory appFactory;
#Mock private UserPojo userPojo;
#Before
public void setUpBeforeClass() throws Exception {
appDAOObj = mock(UserPojoDaoImpl.class);
appFactory = mock(ApplicationDAOfactory.class);
//MockitoAnnotations.initMocks(WelcomeUser.class);
new WelcomeUser(appDAOObj, appFactory);
}
#Test
public void testWelcome() throws Exception{
when(appFactory.getUserPojoDaoInstance()).thenReturn(appDAOObj);
when(appDAOObj.persistUser(userPojo)).thenReturn(userPojo);
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name" ,"user");
paramMap.put("email" ,"user#user.com");
ActionProxy proxy = getActionProxy("/submitUser");
ActionContext actionContext= proxy.getInvocation().getInvocationContext();
actionContext.setParameters(paramMap);
String result= proxy.execute();
assertEquals("success", result);
}
}
My doubt is that although I am trying to mock the behavior upon which my welcome method in the struts action class depends but it doesn't seems to be working. I have browsed through various sources but it has all gone in vain. As far as I have been able to comprehend this situation my best guess is that when I call the execute method upon the proxy instance in my test method the control does execute the welcome method as per the mapping in my struts.xml file but when execution arrives at the point where I am expecting my mocks to work it doesn't works and hits my database which I don't want. I do understand there is certainly a gap in my understanding but any help shall be appreciated. Cheers!!
I had similar issue but my case was bit different as I was using setter Injector through spring framework and my action class already had setter method for Dao.
I had to get the action from proxy and Inject mocked Dao object into my action.
I did following before executing proxy :
WelcomeUser actionObj = (WelcomeUser) proxy.getAction();
actionObj.setDaoObj(appDAOObj);
you have to figure out a way to inject mocked objects into actionObj .
Update :
Check if following works for you
WelcomeUser actionObj = (WelcomeUser) proxy.getAction();
ReflectionTestUtils.setField(actionObj, "appDAOObj", appDAOObj);
ReflectionTestUtils.setField(actionObj, "appFactory", appFactory);
String result= proxy.execute();
assertEquals("success", result);
Make sure you have spring-test-x.x.x.RELEASE.jar and spring-core-x.x.x.RELEASE.jar (Including any other dependency) in your classpath.

jUnits for backing bean with contructer

I want to write jUnit test cases for methods which are in backing bean but the problems is that bean's constructer has some calls to "facesContext" methods. calls are like this
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().
put(
BEAN_NAME,
BEAN_OBJECT
);
If I write any test case it throws "NullPointerException". I know that it is because facesContext is not initialized.
For example If I have a method like this
public String disableFields() throws ApplicationException
{
logger.info(empId);
logger.info(relationShip.getRelationshipName());
if(relationShip.getRelationshipName().equalsIgnoreCase("select"))
{
errorMessage="Please select relationship";
Utils.addMessage(errorMessage, FacesMessage.SEVERITY_ERROR);
return null;
}
showEmpName=true;// boolean value
return null;
}
kindly suggest me with code of jUnit test case if possible......
please suggest any way to write jUnits test cases for these type of methods....I am using jsf 1.2..
thanks in advance
You'll need PowerMockito's feature for mocking static methods as explained here: https://code.google.com/p/powermock/wiki/MockStatic
Here's a working example:
import org.hamcrest.core.IsEqual;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.faces.application.FacesMessage;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Utils.class)
public class AppTest {
public static final String PLEASE_SELECT_RELATIONSHIP = "Please select relationship";
#Test
public void testDisableFields() throws Exception {
PowerMockito.mockStatic(Utils.class);
Relationship relationShip = Mockito.mock(Relationship.class);
App app = new App(1, relationShip);
Mockito.when(relationShip.getRelationshipName()).thenReturn("SeLeCt");
app.disableFields();
Assert.assertThat(app.getErrorMessage(), IsEqual.equalTo(PLEASE_SELECT_RELATIONSHIP));
PowerMockito.verifyStatic(Mockito.times(1));
Utils.addMessage(PLEASE_SELECT_RELATIONSHIP, FacesMessage.SEVERITY_ERROR);
}
}

Mocking FacesContext

I am trying to add some unit tests to a JSF application. This application didnt rely heavily on any best practices, so many service methods use the FacesContext to pull data from managed session beans like so:
(this is inside a util class)
public static Object getPageBean(String beanReference) {
FacesContext fc = FacesContext.getCurrentInstance();
VariableResolver vr = fc.getApplication().getVariableResolver();
return vr.resolveVariable(fc, beanReference);
}
What would be the best way to mock this? I am using groovy so i have a few more options for creating classes that i cant normally create.
You can return a mock context via FacesContext.getCurrentInstance by invoking setCurrentInstance(FacesContext) before running the test. The method is protected, but you can access it either via reflection or by extending FacesContext. There is a sample implementation using Mockito here.
This url provides a really good article on it:
http://illegalargumentexception.blogspot.com/2011/12/jsf-mocking-facescontext-for-unit-tests.html
You have your managed bean:
package foo;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#RequestScoped
public class AlphaBean {
public String incrementFoo() {
Map<String, Object> session = FacesContext.getCurrentInstance()
.getExternalContext()
.getSessionMap();
Integer foo = (Integer) session.get("foo");
foo = (foo == null) ? 1 : foo + 1;
session.put("foo", foo);
return null;
}
}
You stub out the FacesContext:
package foo.test;
import javax.faces.context.FacesContext;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public abstract class ContextMocker extends FacesContext {
private ContextMocker() {
}
private static final Release RELEASE = new Release();
private static class Release implements Answer<Void> {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
setCurrentInstance(null);
return null;
}
}
public static FacesContext mockFacesContext() {
FacesContext context = Mockito.mock(FacesContext.class);
setCurrentInstance(context);
Mockito.doAnswer(RELEASE)
.when(context)
.release();
return context;
}
}
Then write your unit test:
#Test
public void testIncrementFoo() {
FacesContext context = ContextMocker.mockFacesContext();
try {
Map<String, Object> session = new HashMap<String, Object>();
ExternalContext ext = mock(ExternalContext.class);
when(ext.getSessionMap()).thenReturn(session);
when(context.getExternalContext()).thenReturn(ext);
AlphaBean bean = new AlphaBean();
bean.incrementFoo();
assertEquals(1, session.get("foo"));
bean.incrementFoo();
assertEquals(2, session.get("foo"));
} finally {
context.release();
}
}
You could use for example PowerMock which is a framework that allows you to extend mock libraries like Mockito with extra capabilities. In this case it allows you to mock the static methods of FacesContext.
If you are using Maven, use following link to check the needed dependency setup.
Annotate your JUnit test class using these two annotations. The first annotation tells JUnit to run the test using PowerMockRunner. The second annotation tells PowerMock to prepare to mock the FacesContext class.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ FacesContext.class })
public class PageBeanTest {
Mock FacesContext using PowerMock and use verify() of Mockito in order to check that resolveVariable() was called with the expected parameters.
#Test
public void testGetPageBean() {
// mock all static methods of FacesContext
PowerMockito.mockStatic(FacesContext.class);
FacesContext facesContext = mock(FacesContext.class);
when(FacesContext.getCurrentInstance()).thenReturn(facesContext);
Application application = mock(Application.class);
when(facesContext.getApplication()).thenReturn(application);
VariableResolver variableResolver = mock(VariableResolver.class);
when(application.getVariableResolver()).thenReturn(variableResolver);
PageBean.getPageBean("bean_reference");
verify(variableResolver)
.resolveVariable(facesContext, "bean_reference");
}
I've created a blog post which explains the above code sample in more detail.
Here's another way to use Mockito and reflection to mock FacesContext and to make sure normal calls to FacesContext.getCurrentInstance() returns the (mocked) instance you want:
#Before
public void setUp() {
// Use Mockito to make our Mocked FacesContext look more like a real one
// while making it returns other Mocked objects
ExternalContext externalContext = Mockito.mock(ExternalContext.class);
Flash flash = Mockito.mock(Flash.class);
FacesContext facesContext = Mockito.mock(FacesContext.class);
Mockito.when(facesContext.getExternalContext()).thenReturn(externalContext);
Mockito.when(externalContext.getFlash()).thenReturn(flash);
// Use Java reflection to set the FacesContext to our Mock, since
// FacesContext.setCurrentInstance() is protected.
try {
Method setter = FacesContext.class.getDeclaredMethod("setCurrentInstance", new Class[]{FacesContext.class});
setter.setAccessible(true);
setter.invoke(null, new Object[]{facesContext});
} catch (Exception e) {
System.err.println("Exception in reflection-based access to FacesContext");
e.printStackTrace();
}
}
(This is adapted / extended from #McDowell's answer below.)
I give you an example to mock FacesConext without using PowerMockito. The idea is to extend a simple class from Facescontext, and change the current instance using protected static method setCurrentInstance:
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.sun.faces.config.InitFacesContext;
public class DummyTest {
#Mock
private FacesContext context;
#Before
public void before(){
MockitoAnnotations.initMocks(this);
ServletContext sc = mock(ServletContext.class);
new FakeContext(sc);
assertEquals(context, FacesContext.getCurrentInstance());
}
#Test
public void dummy(){
}
private class FakeContext extends InitFacesContext{
public FakeContext(ServletContext sc) {
super(sc);
setCurrentInstance(context);
}
}
}
in my case i was able to mock it in pure groovy.
i provide a map of MockBeans that it can return:
private FacesContext getMockFacesContext(def map){
def fc = [
"getApplication": {
return ["getVariableResolver": {
return ["resolveVariable": { FacesContext fc, String name ->
return map[name]
}] as VariableResolver
}] as Application
},
"addMessage": {String key, FacesMessage val ->
println "added key: [${key}] value: [${val.getDetail()}] to JsfContext messages"
},
"getMessages": {return null}
] as FacesContext;
return fc;
}
I believe the best solution is not presented here. Here we go
#RunWith(PowerMockRunner.class)
#PrepareForTest({ FacesContext.class})
public class MyTestClass{
#Mock
private FacesContext facesContext;
#Before
public void init() throws Exception {
PowerMockito.mockStatic(FacesContext.class);
PowerMockito.when(FacesContext.getCurrentInstance()).thenReturn(facesContext);
}
And you need to import all the PowerMockito bundle in your pom.xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>