Write Unit test case using HttpServlet - unit-testing

I have this unit test, it compiles and runs well. How can I represent this in a test case document for my unit test (Id, purpose, preconditions, input and expected output). What would be the input and output since I don't know the actual input of the httpservletrequest and don't know either the response (httpservletresponse). I just mocked these objects so I can perform my unit test. I was planning to do 'AssertEquals' but I don't know what could be the expected output.
#Test
public void testSearchPanelists() throws IOException {
HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
HttpServletResponse res = Mockito.mock(HttpServletResponse.class);
HttpSession hs = Mockito.mock(HttpSession.class);
PowerMockito.mockStatic(SearchPanelist.class);
Controller.searchPanelists(req, res, hs);
PowerMockito.verifyStatic(SearchPanelist.class);
SearchPanelist.searchPanelists(req,res,hs);
}
I have this in Controller class:
public static void searchPanelists(HttpServletRequest req, HttpServletResponse res, HttpSession hs) throws IOException
{
SearchPanelist.searchPanelists(req, res, hs);
}
and this in SearchPanelist class:
public static void searchPanelists(HttpServletRequest req, HttpServletResponse res, HttpSession hs) throws IOException
{
HashMap<String, String> searchCriteria = new HashMap<String, String>();
//Let's pull the values from the search form.
searchCriteria.put("FirstName", req.getParameter("pFName"));
searchCriteria.put("LastName", req.getParameter("pLName"));
searchCriteria.put("Institution", req.getParameter("pInstitution"));
searchCriteria.put("Address", req.getParameter("pAddress"));
searchCriteria.put("City", req.getParameter("pCity"));
searchCriteria.put("State", req.getParameter("pState"));
searchCriteria.put("ZipCode", req.getParameter("pZip"));
searchCriteria.put("Telephone", req.getParameter("pTelephone"));
searchCriteria.put("Email", req.getParameter("pEmail"));
searchCriteria.put("Gender", req.getParameter("pGender"));
searchCriteria.put("Ethnicity", req.getParameter("pEthnicity"));
searchCriteria.put("Expertise", req.getParameter("pExpertise"));
searchCriteria.put("ISCID", req.getParameter("pISCID"));
ArrayList<PanelistProfile> userProfile = DBManager.getPanelists(searchCriteria);
if(userProfile == null)
res.sendRedirect("messagePage?messageCode=No Panelists Found.");
else
{
hs.setAttribute("Panelists", userProfile);
res.sendRedirect("displayPanelists.jsp");
}
}

Related

MapReduce - Mock with Mokito

I have the a reducer class that I wanted to write test cases:
Reduce class:
public class MyReducer extends Reducer<Text, Text, NullWritable, Text> {
private static final Logger LOG = LogManager.getLogger(MyReducer.class);
public static List<String> l1 = new ArrayList<String>();
String id = null;
private MultipleOutputs<NullWritable, Text> mos;
#Override
public void setup(final Context context) throws IOException, InterruptedException {
mos = new MultipleOutputs<NullWritable, Text>(context);
final Path[] uris = DistributedCache.getLocalCacheFiles(context.getConfiguration());
try {
final BufferedReader readBuffer1 = new BufferedReader(new FileReader(uris[0].toString()));
String line;
while ((line = readBuffer1.readLine()) != null) {
l1.add(line);
}
readBuffer1.close();
} catch (Exception e) {
LOG.error(e);
}
}
public void reduce(final Text key, final Iterable<Text> values, final Context context)
throws IOException, InterruptedException {
final String[] key1 = key.toString().split("-");
final String keyA = key1[10];
final String date = key1[1];
/* Some condition check */
mos.write(NullWritable.get(), new Text(inputEventValue), keyA + "//date=" +
date.substring(0, 4) + "-" + date.substring(4, 6));
}
#Override
public void cleanup(final Context context) throws IOException, InterruptedException {
mos.close();
}
}
Test Case looks like :
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock
private MyReducer.Context mockContext;
MyReducer reducer;
MultipleOutputs<NullWritable, Text> mos;
#Before
public void setUp() {
reducer = new MyReducer();
}
#Test
public void myReducerTest() throws Exception {
MyReducer spy = PowerMockito.spy(new MyReducer());
doNothing().when(spy).setup(mockContext);
mos = new MultipleOutputs<NullWritable, Text>(mockContext);
List<Text> sline = new ArrayList<>() ;
List<String> l1 = new ArrayList<String>();
l1.add(“1234”);
sline.add(new Text(“xyz”));
Whitebox.setInternalState(MyReducer.class,”l1", l1);
Whitebox.setInternalState(MyReducer.class,"mos",mos);
reducer.reduce(new Text(“xyz-20200101-1234),sline,mockContext);
}
#After
public void tearDown() throws Exception {
/*
* this will do the clean up part
*/
verifyNoMoreInteractions(mockContext);
}
When running in Debug mode it goes to the reducer's reduce method and fails with NullPointerException where mos write statement is?
Complete Stack trace:
java.lang.NullPointerException
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.getNamedOutputsList(MultipleOutputs.java:196)
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.<init>(MultipleOutputs.java:324)
at MyTest.myeducerTest
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
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:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
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:118)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
Mocking mos errors as mos is not a static.
Any suggestion.
Junit - ReduceDriver, withInput, withOutput,testRun doesn't work.
Thanks.
I tried mocking Multiple outputs as suggested:
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
#Mock
private MyReducer.Context mockContext;
List<String> namedOut = new ArrayList<>();
namedOut.add("NM1");
namedOut.add("NM2");
MultipleOutputs spy = PowerMockito.spy(new MultipleOutputs<>(mockContext));
when(spy, "getNamedOutputsList(mockContext)").thenReturn(namedOut);
But this gives me error : org.powermock.reflect.exceptions.MethodNotFoundException: no method found with name 'getNamedOutputsList(() anyObject())' with parameter types : [] in class org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.
Looks like you did not define what mockContext.getContext() should return for your test, so it returns null and fails.
Based on this sourcecode the methods looks like this (so you might use a different version):
private static List<String> getNamedOutputsList(JobContext job) {
List<String> names = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(
job.getConfiguration().get(MULTIPLE_OUTPUTS, ""), " ");
while (st.hasMoreTokens()) {
names.add(st.nextToken());
}
return names;
}
JobContext seems to refer to your mock Reducer.Context mockContext, so you need to define the appropriate behaviour so that it returns what it is supposed to return.
Note that this call originates from the constructor of MultipleOutputs.
Also take note of the static getCountersEnabled method that is invoked from the constructor and interacts with the context.
Mocking mos errors as mos is not a static.
You could probably use reflections to put a mocked version of mos into your MyReducer class.
Check here for some example on how to mock a private static field.
Edit:
If you try to mock the conig do it like this:
Configuration config = Mockito.mock(Configuration.class);
when(mockContext.getConfiguration()).thenReturn(config);
As far as I see the get that are invoked on the configuration object always provide a default value, so it shouldn't matter if the key/value pair is in there or not.

Unit Test Async Deferred Result Controller gets hung forever

The controller method I am testing
#GetMapping("/customers")
#ResponseBody
public DeferredResult<ResponseEntity<Resources<Resource<Customer>>>> getAllCustomers(
#PageableDefault(page = 0, size = 20) #SortDefault.SortDefaults({
#SortDefault(sort = "name", direction = Direction.ASC) }) Pageable pageable,
PagedResourcesAssembler<Customer> assembler, HttpServletRequest request) {
DeferredResult<ResponseEntity<Resources<Resource<Customer>>>> response = new DeferredResult<>(
Long.valueOf(1000000));
response.onTimeout(() -> response
.setErrorResult(ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body("Request timed out.")));
response.onError((Throwable t) -> {
response.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occured."));
});
ListenableFuture<Page<Customer>> future = customerService.findAll(pageable);
future.addCallback(new ListenableFutureCallback<Page<Customer>>() {
#Override
public void onSuccess(Page<Customer> result) {
Link self = new Link(
ServletUriComponentsBuilder.fromRequestUri(request).buildAndExpand().toUri().toString(),
"self");
LOGGER.debug("Generated Self Link {} for Customer Resource Collection", self.getHref());
if (result.hasContent())
response.setResult(
ResponseEntity.ok(assembler.toResource(result, customerResourceAssembler, self)));
else
response.setErrorResult(ResponseEntity.notFound());
LOGGER.debug("Returning Response with {} customers", result.getNumber());
}
#Override
public void onFailure(Throwable ex) {
LOGGER.error("Could not retrieve customers due to error", ex);
response.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Could not save customers list due to server error."));
}
});
return response;
}
the unit test
#RunWith(SpringRunner.class)
#WebMvcTest(CustomerController.class)
#EnableSpringDataWebSupport
#Import({ CustomerResourceAssember.class, BranchResourceAssembler.class, InvoiceResourceAssembler.class,
CustomerAsyncService.class })
public class CustomerControllerTests {
#Autowired
private MockMvc mockMvc;
#Autowired
CustomerAsyncService customerService;
#MockBean
private CustomerRepository customerRepository;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testWhenNoCustomersThenReturnsEmptyHALDocument() throws Exception {
// Given
BDDMockito.given(customerRepository.findAll(PageRequest.of(0, 20)))
.willReturn(new PageImpl<Customer>(Collections.emptyList()));
// When
MvcResult result = mockMvc.perform(get("/customers").accept(MediaTypes.HAL_JSON_VALUE)).andDo(print())
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult(new PageImpl<Customer>(Collections.emptyList()))).andReturn();
// Then
mockMvc.perform(asyncDispatch(result)).andExpect(status().isOk());
}
This test neve completes, doesn't even time out on my IDE, I have to kill it everytime I run it, if run the entire app however this /customers endpoint gives a 404 when there are no customers added to the application.
What do I need to do make sure this test completes, the CustomerService call ultimately calls CustomerRepository which I have mocked because I couldn't get my brains around how to mock the async call to service method. the customer service class is as follows
#Async
#Service
public class CustomerAsyncService {
private CustomerRepository customerRepository;
#Autowired
public CustomerAsyncService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
#Transactional(readOnly = true, isolation = Isolation.SERIALIZABLE)
public ListenableFuture<Page<Customer>> findAll(Pageable pageable) {
return AsyncResult.forValue(customerRepository.findAll(pageable));
}
I was hoping mocking the Repository method would do the trick. How do I mock the async service call
My bad was using mocks wrongly, this worked
#RunWith(SpringRunner.class)
#WebMvcTest(CustomerController.class)
#Import({ CustomerResourceAssember.class, BranchResourceAssembler.class, InvoiceResourceAssembler.class,
CustomerAsyncService.class })
public class CustomerControllerTests {
#MockBean
private CustomerRepository customerRepository;
#InjectMocks
CustomerAsyncService customerService = new CustomerAsyncService(customerRepository);
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
JacksonTester.initFields(this, objectMapper);
}
#Test
public void testReturnsNotFoundForEmptyGetAllCustomersResult() throws Exception {
// Given
Page<Customer> emptyPage = new PageImpl<Customer>(Collections.emptyList());
BDDMockito.given(customerRepository.findAll(any(Pageable.class))).willReturn(emptyPage);
// When
MvcResult result = mockMvc.perform(get("/customers")).andExpect(request().asyncStarted()).andDo(print()).andReturn();
// Then
mockMvc.perform(asyncDispatch(result)).andDo(print()).andExpect(status().isNotFound());
}
}

Unit Testing StreamingOuput as Response entity Jersey

I am doing something similar to mentioned in
Example of using StreamingOutput as Response entity in Jersey
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response streamExample(#Context UriInfo uriInfo) {
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream os) throws IOException,WebApplicationException {
try{
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
//Read resource from jar
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("public/" + uriInfo.getPath());
...//manipulate the inputstream and build string with StringBuilder here//.......
String inputData = builder.toString();
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
writer.write(inputData);
writer.flush();
} catch (ExceptionE1) {
throw new WebApplicationException();
}
}
};
return Response.ok(stream,MediaType.APPLICATION_OCTET_STREAM).build();
}
I am trying to unit test this by mocking URIInfo like mentioned in How to get instance of javax.ws.rs.core.UriInfo
public void testStreamExample() throws IOException, URISyntaxException {
UriInfo mockUriInfo = mock(UriInfo.class);
Mockito.when(mockUriInfo.getPath()).thenReturn("unusal-path");
Response response = myresource.streamExample(mockUriInfo);}
I want to be able to check that I get an Exception when I switch the path to jar to something else.But, when I run/debug the test, I never enter the
public void write(OutputStream os) throws IOException,
WebApplicationException {...}
part and I only always hit the return Response.ok(stream,MediaType.APPLICATION_OCTET_STREAM).build();
Am I missing something very obvious here??
Because the stream is not written to until it hits the MessageBodyWriter (which is the component that ends up calling the StreamingOutput#write).
What you can do, is just get the Response from the return and call Response#getEntity() (which returns an Object) and cast it to StreamingOutput. Then call the write method yourself, passing an OutputStream, maybe a ByteArrayOutputStream so you can get the contents as a byte[] to check it. It all would look something like
UriInfo mockInfo = mockUriInfo();
Response response = resource.streamExample(mockInfo);
StreamingOutput output = (StreamingOutput) response.getEntity();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
output.write(baos);
byte[] data = baos.toByteArray();
String s = new String(data, StandardCharsets.UTF_8);
assertThat(s, is("SomeCharacterData"));

How to use camel mock to get full XML?

In a unit test with camel, I can make asserts using xpath to check if the output xml is correct. But instead, I'd like to use XMLUnit to validate the xml against another entire xml file. Is that possible? The following test succeeds, but I'd like to adjust it to get the actual XML.
#Test
public void testSupplierSwitch() throws Exception
{
MockEndpoint mock = getMockEndpoint("mock:market-out");
mock.expectedMessageCount(1);
EdielBean edielBean = (EdielBean)context.getBean("edielbean");
edielBean.startSupplierSwitch(createCustomer(), createOrder(), "54", "43");
assertMockEndpointsSatisfied();
}
Here is one example of how you can solve it, using mockEndpoint.getExchanges()
public class XmlUnitTest extends CamelTestSupport{
#EndpointInject(uri = "mock:market-out")
MockEndpoint marketOut;
#Override
#Before
public void setUp() throws Exception {
super.setUp();
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:in")
.setBody(constant("<xml>data</xml>"))
.to(marketOut.getEndpointUri());
}
});
}
#Test
public void sameXml() throws Exception {
marketOut.expectedMessageCount(1);
template.sendBody("direct:in", "body");
marketOut.assertIsSatisfied();
final String actual = marketOut.getExchanges().get(0).getIn().getBody(String.class);
final Diff diff = XMLUnit.compareXML("<xml>data</xml>", actual);
assertTrue(diff.similar());
assertTrue(diff.identical());
}
#Test()
public void notSameXml() throws Exception {
marketOut.expectedMessageCount(1);
template.sendBody("direct:in", "body");
marketOut.assertIsSatisfied();
final String actual = marketOut.getExchanges().get(0).getIn().getBody(String.class);
final Diff diff = XMLUnit.compareXML("<xml>invalid</xml>", actual);
assertFalse(diff.similar());
assertFalse(diff.identical());
}
}

Async request slow performance

I'm making a web based scoring system for a robotic competition. When a point is scored, I want to refresh the page of everybody watching the game. My code is working "correctly".
My problem is that when I test and I open about 5 to 10 web pages, any other pages that I request are not processed until I close some pages. I think that what's happening is that request.startAsync() is not releasing the thread and it's waiting infinitely.
I've tested on both Jetty 9.2.7.v20150116 and Tomcat7. Both have the same slow behavior.
// Display a game with all it's events
// http://stackoverflow.com/questions/10878243/sse-and-servlet-3-0
#WebServlet(urlPatterns = { "/gameRefresh" }, asyncSupported = true)
public class GameRefreshController extends HttpServlet
{
private static final long serialVersionUID = -6890088129187673292L;
private static AtomicBoolean refreshNeeded = new AtomicBoolean();
private final Queue<AsyncContext> ongoingRequests = new ConcurrentLinkedQueue<>();
private ScheduledExecutorService service;
public static void setRefreshNeeded(boolean value)
{
refreshNeeded.set(value);
}
#Override
public void init(ServletConfig config) throws ServletException
{
final Runnable notifier = new Runnable()
{
#Override
public void run()
{
// Don't refresh if it's not needed.
if(!refreshNeeded.get())
{
return;
}
// This var is set by the backend when an event occurs.
setRefreshNeeded(false);
final Iterator<AsyncContext> iterator = ongoingRequests.iterator();
// not using for : in to allow removing items while iterating
while (iterator.hasNext())
{
AsyncContext asyncContext = iterator.next();
final ServletResponse servletResponse = asyncContext.getResponse();
PrintWriter out;
try
{
out = servletResponse.getWriter();
String toOutput = "data: refresh\n\n";
out.write(toOutput);
out.checkError();
}
catch(IOException exception)
{
// iterator is always removed because we refresh the whole page.
}
finally
{
iterator.remove();
}
}
}
};
service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(notifier, 1, 1, TimeUnit.SECONDS);
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
final AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
asyncContext.addListener(new AsyncListener()
{
#Override
public void onComplete(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
#Override
public void onTimeout(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
#Override
public void onError(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
#Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
});
ongoingRequests.add(asyncContext);
}
}