I have some problem with wirint testcase for my JSF app. So i want to test my logout method:
FacesContext context = EasyMock.createMock(FacesContext.class);
String userName = "testUserName";
HttpSession session = EasyMock.createMock(HttpSession.class);
ExternalContext ext = EasyMock.createMock(ExternalContext.class);
EasyMock.expect(ext.getSession(true)).andReturn(session);
EasyMock.expect(context.getExternalContext()).andReturn(ext).times(2);
context.getExternalContext().invalidateSession();
EasyMock.expectLastCall().once();
EasyMock.replay(context);
EasyMock.replay(ext);
EasyMock.replay(session);
loginForm = new LoginForm();
loginForm.setUserName(userName);
String expected = "login";
String actual = loginForm.logout();
context.release();
Assert.assertEquals(expected, actual);
EasyMock.verify(context);
EasyMock.verify(ext);
EasyMock.verify(session);
My logout method is:
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/authentication/login.xhtml?faces-redirect=true";
}
My problem is that i got a nullpointer exception here:
EasyMock.expectLastCall().once()
How should it be properly tested? I guess it is something with the mocks but i couldnt find a solution, how could i mock properly the FacesContext in this case
In order to make the above work you could use for example PowerMock which is a framework that allows you to extend mock libraries like EasyMock 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 LoginFormTest {
Now go ahead and mock FacesContext using PowerMock like you would do for the other classes. Only difference is that this time you perform replay() and verify() on the class not the instance.
#Test
public void testLogout() {
// mock all static methods of FacesContext
PowerMock.mockStatic(FacesContext.class);
FacesContext context = EasyMock.createMock(FacesContext.class);
ExternalContext ext = EasyMock.createMock(ExternalContext.class);
EasyMock.expect(FacesContext.getCurrentInstance()).andReturn(context);
EasyMock.expect(context.getExternalContext()).andReturn(ext);
ext.invalidateSession();
// expect the call to the invalidateSession() method
EasyMock.expectLastCall();
context.release();
// replay the class (not the instance)
PowerMock.replay(FacesContext.class);
EasyMock.replay(context);
EasyMock.replay(ext);
String userName = "testUserName";
LoginForm loginForm = new LoginForm();
loginForm.setUserName(userName);
String expected = "/authentication/login.xhtml?faces-redirect=true";
String actual = loginForm.logout();
context.release();
Assert.assertEquals(expected, actual);
// verify the class (not the instance)
PowerMock.verify(FacesContext.class);
EasyMock.verify(context);
EasyMock.verify(ext);
}
I've created a blog post which explains the above code sample in more detail.
This:
FacesContext context = EasyMock.createMock(FacesContext.class);
does not change the return value from this (in the class being tested):
FacesContext.getCurrentInstance()
You need to extend FacesContext then call the protected method setCurrentInstance with your mocked FacesContext.
Related
I'm trying to mock the return value for a method using the when call from mockito. However, I'm new to this and I may perhaps be misunderstanding how mockito works, since the call is failing inside the method mocked when that calls another method. I thought regardless of how that method is implemented, I should be getting the return value I'm asking for? Or do I need to mock also the internals for that method? I feel that shouldn't be it.
public boolean verifyState(HttpServletRequest request, String s) {
String stateToken = getCookieByName(request, STATE_TOKEN);
String authToken = getCookieByName(request, AUTHN);
boolean isValidState = true;
if (isValidState) {
try {
log.info(getEdUserId(stateToken, authToken));
return true;
} catch (Exception e) {
ExceptionLogger.logDetailedError("CookieSessionUtils.verifyState", e);
return false;
}
} else {
return false;
}
}
public String getEdUserId(String stateToken, String authToken) throws Exception {
String edUserId;
Map<String, Object> jwtClaims;
jwtClaims = StateUtils.checkJWT(stateToken, this.stateSharedSecret); // Failing here not generating a proper jwt token
log.info("State Claims: " + jwtClaims);
edUserId = sifAuthorizationService.getEdUserIdFromAuthJWT(authToken);
return edUserId;
}
My test:
#ActiveProfiles(resolver = MyActiveProfileResolver.class)
#WebMvcTest(value = CookieSessionUtils.class, includeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {ApiOriginFilter.class, ValidationFilter.class})})
class CookieSessionUtilsTest {
#Autowired
private CookieSessionUtils cookieSessionUtils; // Service class
#Mock
private CookieSessionUtils cookieSessionUtilsMocked; // Both the method under test and the one mocked are under the same class, so trying these two annotations together.
#Mock
private HttpServletRequest request;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testVerifyState1() throws Exception {
//...Some mocks for getCookieName
UUID uuid = UUID.randomUUID();
when(cookieSessionUtils.getEdUserId(anyString(), anyString()).thenReturn(eq(String.valueOf(uuid))); // When this line runs it fails on verifyState method
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
UPDATE
Attempt using anyString() instead of eq().
Thank you.
Your test is broken in a few places.
Setting expectations on a real object
You should call Mockito.when on mocks and spies, not on System under test. Mockito normally reports it with a clear error message, but you throw a NPE from getEdUserId, so this is reported instead. The NPE stems from the fact that both eq and anyString return null, which is passed to the real method.
Invalid use of matchers
As #StefanD explained in his answer eq("anyString()") is not matching any string. It matches only one string "anyString()"
Returning a mather instead of real object
thenReturn(eq(String.valueOf(uuid)))
This is illegal position for a matcher.
Mixing Mockito and Spring annotations in a WebMvcTest
This is a common error. Mockito does not inject beans to the spring context.
From the code provided it is unclear what CookieSessionUtils is (Controller? ControllerAdvice?) and what is the correct way to test it.
Update
It seems that you are trying to replace some methods under test. A way to do it is to use a Spy.
See https://towardsdatascience.com/mocking-a-method-in-the-same-test-class-using-mockito-b8f997916109
The test written in this style:
#ExtendWith(MockitoExtension.class)
class CookieSessionUtilsTest {
#Mock
private HttpServletRequest request;
#Mock
private SifAuthorizationService sifAuthorizationService;
#Spy
#InjectMocks
private CookieSessionUtils cookieSessionUtils;
#Test
public void testVerifyState1() throws Exception {
Cookie cookie1 = new Cookie("stateToken", "stateToken");
Cookie cookie2 = new Cookie("Authn", "Authn");
when(request.getCookies()).thenReturn(new Cookie[]{cookie1, cookie2});
UUID uuid = UUID.randomUUID();
doReturn(String.valueOf(uuid)).when(cookieSessionUtils).getEdUserId(anyString(), anyString());
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
}
An alternative way is to call the real method, but to mock all collaborators: StateUtils and sifAuthorizationService. I would probably go with this one, if you want to test public getEdUserId.
Test written when mocking collaborators:
#ExtendWith(MockitoExtension.class)
class CookieSessionUtilsTest {
#Mock
private HttpServletRequest request;
#Mock
private SifAuthorizationService sifAuthorizationService;
#InjectMocks
private CookieSessionUtils cookieSessionUtils;
#Test
public void testVerifyState1() throws Exception {
Cookie cookie1 = new Cookie("stateToken", "stateToken");
Cookie cookie2 = new Cookie("Authn", "Authn");
when(request.getCookies()).thenReturn(new Cookie[]{cookie1, cookie2});
UUID uuid = UUID.randomUUID();
when(sifAuthorizationService.getEdUserIdFromAuthJWT(cookie2.getValue())).thenReturn(String.valueOf(uuid));
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
}
I took the assumption that StateUtils.checkJWT does not need to be mocked
The points above are still valid and need to be resolved in either case.
Remarks
As the system under test is currently a Service, I suggest to drop WebMvcTest and test it with plain mockito instead.
Should SUT be a service? It is more typical to handle auth code in filters.
note usage of doReturn when stubbing a method on a spy.
You use mocks in more places than needed. For example Cookie is trivial to construct, there is no point in using a mock
The error is here:
when(cookieSessionUtils.getEdUserId(eq("anyString()"), eq("anyString()"))).thenReturn(eq(String.valueOf(uuid)));
It should read like
when(cookieSessionUtils.getEdUserId(anyString()), anyString()).thenReturn(uuid);
Please refer to the Mockito documentation of Argument matchers.
Because the argument matchers looking for the string "anyString()" they never match the actual parameters the method call is providing and so there is never returned the uuid you expecting.
abort()-Method:
public void abort() {
LOG.info("some-text");
warning("some-text");
}
warning()-Method:
public void warning(String message) {
FacesContext.getCurrentInstance()
.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "INFO:", message));
}
I want to write a Test-Case for abort wich is just verifying that nothing has changed and a second Test-Case which is verifying that warning() is working.
I´m knowing this little two methods doesn´t need a Unit-Test but I want to know if it´s possible. UI-Test for showing the p:message is working well but I want to check the Caption, Typ and Message by Unittest before because it´s running much faster.
working solution with just using JUnit 4.11
Separate the content from warning() in a own class like this:
#Named
#RequestScoped
public class Resources {
#Produces
public FacesContext produceFacesContext() {
return FacesContext.getCurrentInstance();
}
}
Next you need to define an ArgumentCaptor which can catch the FacesMessage for your JUnit-Test. I´ve created it as a clss member which will be initialized in the #before section and get the null value in #teardown.
private ArgumentCaptor<FacesMessage> facesMessageCaptor;
#Before
public void setUp() {facesMessageCaptor = ArgumentCaptor
.forClass(FacesMessage.class);
}
#After
public void tearDown() { facesMessageCaptor = null; }
Now you just need to add two #Mocks to your test-class
#Mock
Resources resourcesMock;
#Mock
FacesContext facesContextMock;
So you did it! Write the test like this:
Mockito.doReturn(facesContextMock).when(resourcesMock).produceFacesContext();
// Execute Method
cut.warning("SOME_DETAIL_TEXT");
// Verify interactions with the Resources and Faces and maybe others...
verify(resourcesMock).produceFacesContext();
verify(facesContextMock).addMessage(Mockito.anyString() ,
facesMessageCaptor.capture());
verifyNoMoreInteractions(...., resourcesMock, facesContextMock);
// write assert (i´ve used hamcrast-corematchers - more readable)
actualMessage = (FacesMessage) facesMessageCaptor.getValue();
assertThat(FacesMessage.SEVERITY_WARN, is(equalTo(actualMessage.getSeverity())));
assertThat(MY_TITLE, is(equalTo(actualMessage.getSummary())));
assertThat("DETAIL_TEXT", is(equalTo(actualMessage.getDetail())));
I'm trying to get a handle on Mockito and have a situation where I'd like to use a mock object from within the class-under-test (CUT) but it does not appear to be working. I'm pretty sure I'm approaching the solution incorrectly. Here's some code:
CUT:
public class TestClassFacade {
// injected via Spring
private InterfaceBP bpService;
public void setBpService(InterfaceBP bpService) {
this.bpService = bpService;
}
public TestVO getTestData(String testString) throws Exception {
bpService = BPFactory.getSpecificBP();
BPRequestVO bpRequestVO = new BPRequestVO();
InterfaceBPServiceResponse serviceResponse = bpService.getProduct(bpRequestVO);
if (serviceResponse.getMessage().equalsIgnoreCase("BOB")) {
throw new Exception();
} else {
TestVO testVO = new TestVO();
}
return testVO;
}
}
Spring Configuration:
<bean id="testClass" class="com.foo.TestClassFacade">
<property name="bpService" ref="bpService" />
</bean>
<bean id="bpService" class="class.cloud.BPService" />
Mockito Test Method:
#RunWith(MockitoJUnitRunner.class)
public class BaseTest {
#Mock BPService mockBPService;
#InjectMocks TestClassFacade mockTestClassFacade;
String testString = "ThisIsATestString";
BPRequestVO someBPRequestVO = new BPRequestVO();
InterfaceBPServiceResponse invalidServiceResponse = new BPServiceResponse();
#Test (expected = Exception.class)
public void getBPData_bobStatusCode_shouldThrowException() throws Exception {
invalidServiceResponse.setMessage("BOB");
when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);
mockTestClassFacade.getTestData(testString);
verify(mockBPService.getProduct(someBPRequestVO));
}
}
What I'm trying to do is verify that the "if" conditional portion of the CUT (throwing the Exception) is being invoked in the case of a "BOB" message string being returned from the response of the 3rd party class (BPService). However, what's happening is that the "invalidResponse" object that I am trying to return in the "when" statement above isn't actually being returned when I run my mockTestClassFacade in the line below it. Instead, the
InterfaceBPServiceResponse serviceResponse = bpService.getProduct(bpRequestVO);
line in the real method is being invoked and the "serviceResponse" is being used during my test.
How do I get my mockTestClassFacade to use my "invalidServiceResponse" in this situation?
Thanks a lot...if anything isn't clear please let me know!
I think the problem is in bpService = BPFactory.getSpecificBP();.
You're mocking and injecting InterfaceBP into TestClassFacade, but inside the method getTestData you're creating a new InterfaceBP from BPFactory.
So when testing, you're not actually using the mock, but a different object.
If InterfaceBP is created and injected by Spring, you shouldn't need a factory to get an instance.
Continuing from the other answer, you need to mock the behavior of "BPFactory.getSpecificBP()", but Mockito won't let you mock static methods. You'll have to use PowerMock for this test.
When I am testing the Mocked external call, I am not seeing the mocked value of report instead it is Null and my testing is failing. I can see the Mocked value (of report) in the Test Class but not in BusinessServiceImpl class and Application(Method Return) is not modified as I expected.
My Expectation: When I mock the External call in Impl class, mocked value should be available there and rest everything else happen as if real method was called to complete the Unit Testing.
Implementation code:
package com.core.business.service.dp.fulfillment;
import com.core.business.service.dp.payment.PaymentBusinessService;
public class BusinessServiceImpl implements BusinessService { // Actual Impl Class
private PaymentBusinessService paymentBusinessService = PluginSystem.INSTANCE.getPluginInjector().getInstance(PaymentBusinessService.class);
#Transactional( rollbackOn = Throwable.class)
public Application applicationValidation (final Deal deal) throws BasePersistenceException {
Application application = (Application) ApplicationDTOFactory.eINSTANCE.createApplication();
//External Call we want to Mock
String report = paymentBusinessService.checkForCreditCardReport(deal.getId());
if (report != null) {
application.settingSomething(true); //report is Null and hence not reaching here
}
return application;
}
}
The test code:
#Test(enabled = true)// Test Class
public void testReCalculatePrepaids() throws Exception {
PaymentBusinessService paymentBusinessService = mock(PaymentBusinessService.class);
//Mocking External Call
when(paymentBusinessService.checkForCreditCardReport(this.deal.getId())).thenReturn(new String ("Decline by only Me"));
String report = paymentBusinessService.checkForCreditCardReport(this.deal.getId());
// Mocked value of report available here
//Calling Impl Class whose one external call is mocked
//Application is not modified as expected since report is Null in Impl class
Application sc = BusinessService.applicationValidation(this.deal);
}
The main purpose of Mockito is to isolate the tests. As in, when you are testing your BusinessServiceImpl you should mock all its dependencies.
This is exactly what you are trying to do with your example above. Now for the mocking to work, the mocked object has to be injected into the class you are trying to test, in this case the BusinessServiceImpl.
One way of doing this is by passing the dependecy by the contructor of the class, dependency injection. Or you could look at how it can be done with Spring and ReflectionTestUtils.
I got it done and I am successfully able to get the Mocked value without touching the BusinessServiceImpl class at all. Steps I followed are:
1. #Mock PaymentBusinessService paymentBusinessService = mock(PaymentBusinessService.class);
2. #InjectMocks private PaymentBusinessService paymentBusinessService = PluginSystem.INSTANCE.getPluginInjector().getInstance(PaymentBusinessService.class);
And then simply ran the above test and I could see the value of report as "Decline by only Me" in the BusinessServiceImpl and my test case passed
I'm fairly new to Mockito, and figured I would try to use it to test a SOAP Handler. However, this is turning out to be a much more painful than I would have expected/desired.
I'm looking to validate that my handler is able to extract the messageID in the header of a SOAPMessage. However, from the handler, the only way to get to the header is via the context/message/part/envelope/header. Using Mockito my solution was to mock my SOAPMessage, meant creating each individual object, and stubbing the method.
I can only imagine that there is an easier/cleaner way of accomplishing this:
#RunWith(MockitoJUnitRunner.class)
public class UUIDHandlerTest {
#Mock private SOAPMessage message;
#Mock private SOAPEnvelope envelope;
#Mock private SOAPHeader header;
#Mock private SOAPPart part;
#Mock
private SOAPMessageContext context;
#Before
public void setup() throws SOAPException{
when( context.getMessage()).thenReturn(message);
when( message.getSOAPPart()).thenReturn(part);
when( part.getEnvelope()).thenReturn(envelope);
when( envelope.getHeader()).thenReturn(header);
}
#Test
public void testHandleInboundMessage() {
when( context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).thenReturn(false);
when(header.getElementsByTagName(anyString())).thenAnswer(new Answer<NodeList>() {
/* (non-Javadoc)
* #see org.mockito.stubbing.Answer#answer(org.mockito.invocation.InvocationOnMock)
*/
#Override
public NodeList answer(InvocationOnMock invocation) throws Throwable {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new ByteArrayInputStream(new String("<wsa:MessageID>messageId</wsa:MessageID>").getBytes()));
// TODO Auto-generated method stub
return doc.getElementsByTagName("wsa:MessageID");
}
});
// call the test class
new UUIDHandler().handleMessage(context);
// check the MDC value
assertEquals("messageId", MDC.get(LoggerConstants.DC_PROPERTY_MESSAGE_ID));
}
}
Like I said, it works, but it looks like a very ugly/heavy weight solution.
Is there anyway to do this easier/cleaner?
Thanks!
Eric
SOAPMessageContext context =
mock(SOAPMessageContext.class, RETURNS_DEEP_STUBS);
when(context.getMessage().getSOAPPart().getEnvelope().
getHeader().getElementsByTagName(anyString())).
then(...);
Please also pay attention to the notes on using deep stubs in the mockito documentation.
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#RETURNS_DEEP_STUBS
Annotation style:
#Mock(answer = Answers.RETURNS_DEEP_STUBS) SOAPMessageContext context;
A bit late here, but I prefer spawning a working Endpoint which proxies a mockito mock. This lets me test the whole stack, including interceptors and/or handlers, which should be helpful for your use-case.
I've put up a simple JUnit Rule which simplifies things somewhat here. The resulting test-cases should be small and clean. I recommend loading test XML responses directly from XML files, because that is faster and more simple to maintain.
Don't mock things like this.
Listen to the code... its telling you that this is not the right way to do it.
Rather, just create a (real) message that has some known data in it, and assert that your code does the right stuff with it.
e.g.
MessageIdExtractor extractor = new MessageIdExtractor(); // <- class you are testing
String expectedMessageId = "xxxxxx";
Message m = new SOAPMessage( ).setMessageId(expectedMessageId);
assertThat(extractor.extractIdFrom(m), equalTo(expectedMessageId));