Is there any other way to put parameter of MockMVC? - unit-testing

I am currently testing api endpoints using Spring MockMvc and junit.
It just works fine with the following code.
public void testGetMethod(String url, String locale, String empKey, String accessToken) throws Exception {
mockMvc.perform(get(url).param("locale", locale).param("empKey", empKey).param("accessToken", accessToken))
.andDo(print())
.andExpect(status().isOk());
}
But the thing is when I am trying to modify this code
as follows (for setting parameters with .properties file later),
I am getting 400 code with message, "Required String parameter 'locale' is not present".
public void testGetMethod_param(String url, String locale, String empKey, String accessToken) throws Exception {
MultiValueMap<String, Object> paraMap =new LinkedMultiValueMap<>();
paraMap.add("locale", locale);
paraMap.add("empKey", empKey);
paraMap.add("accessToken", accessToken);
mockMvc.perform(get(url))
.andDo(print())
.andExpect(status().isOk());
}
Can anybody point out what I'm doing wrong here?

You need to add the paraMap to the get request.
mockMvc.perform(get(url).params(paraMap))
.andDo(print())
.andExpect(status().isOk());

Related

Wso2 XACML get custom attributes

I am using Wso2 IS 5.11.0, I have a requirement where I need to fetch the user attributes by calling web-service based.
Below is the sample attribute finder code:
public class CustomPIPAttributeFinder extends AbstractPIPAttributeFinder {
private static final String PIP_NAME = "CustomPIPAttributeFinder";
private static final Set<String> SUPPORTED_ATTRIBUTES;
private static final Log log = LogFactory.getLog(CustomPIPAttributeFinder.class);
static {
SUPPORTED_ATTRIBUTES = new HashSet<String>();
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_ATTRIBUTE_ID);
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_ATTRIBUTE_NAME);
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_CATEGORY);
}
#Override
public Set<String> getAttributeValues(URI attributeType, URI attributeId, URI category, String issuer,
EvaluationCtx evaluationCtx) throws Exception {
//code
}
private String retrieveSampleName(String accessToken) {
String sampleName = null;
// TODO: Get the value of the sample name from the sampleID from the datasource
return sampleName;
}
/**
* Since we override the {#link #getAttributeValues(URI, URI, URI, String, EvaluationCtx)} this won't be called.
*/
#Override
public Set<String> getAttributeValues(String subject, String resource, String action, String environment,
String attributeId, String issuer) throws Exception {
throw new UnsupportedOperationException("Method unsupported in the context");
}
public void init(Properties properties) throws Exception {
}
public String getModuleName() {
return PIP_NAME;
}
public Set<String> getSupportedAttributes() {
return SUPPORTED_ATTRIBUTES;
}
}
In the sample code we can fetch only one attribute per request.But how can we return multiple attributes before executing policy or get multiple attributes in one request from custom attribute finder. Is there any way to achieve this flow.
As per above code request attribute find(returns only one) in the example it will increase the overhead as for each attribute lookup we are calling web-service every time as it'll increase overhead.

Springboot Requestmapper Regexpression

In my Springboot-Controller my Requestmapping method should support flexible subdirectory names. For that I like to use real regexpression. I have tested my regex and it works fine outside of SpringBoot and RequestMapping, however on top of RequestMapping it does not work.
If any http-requests gets in with
http://dir1 or http://dir2
my Method getFile should be called, but it doesn't.
#RequestMapping(value = "{reg:\\/(dir1|dir2)+}", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, HttpServletRequest requ) throws IOException {
}
My question is how to accomplish this ....
The regex-based #RequestHandler can be achieved through (for more)
#RequestMapping(value = "{reg:regexPattern}", method = RequestMethod.GET)
public void getFile(HttpServletRequest request, HttpServletResponse response,
#PathVariable String reg) throws IOException {
...
}
But in your case, the regex pattern is a directory value that contains Slash("/") makes request handler difficult to find the exact mapping. Instead of #PathVariable, you can use #RequestParam
#RequestMapping(value = "\", method = RequestMethod.GET)
public void getFile(HttpServletRequest request, HttpServletResponse response,
#RequestParam("dir") String dir) throws IOException {
...
}
The solution is (Dirk Deyne gave me the hint) that the Slashes have to be outside the regexpression. Here is the solution, where I have extended the value with another subdir filedir to make it more clear:
#RequestMapping(value = "/{subdir:[dir1|dir2]+}/filedir", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, HttpServletRequest requ) {
...
}
This will serve the following incoming requests:
http://localhost:8080/dir1/filedir
http://localhost:8080/dir2/filedir
Thank you!

How to send a property as a string in RestEasy response?

I have a class called Product which has a property called id of type long. Below is the class
public class Product {
private long id;
}
The value of id is beyond the value which javascript can handle. I realized this after seeing the below link
Parse json in javascript - long numbers get rounded
I dont want to declare the field as String in the domain class. But I want to say to RestEasy that it has to send the value as a string in the json response.
How can I do this? I dont want to use any third party api. Is it possible in RestEasy. I have gone through the documentation but did not find any such annotation or may be I did not go through the documentation properly.
Can anyone please help. Thanks all in advance.
If you are using Jackson as JSON Serializer you can extend the JacksonJsonProvider:
#Provider
public class JsonProvider extends org.codehaus.jackson.JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = locateMapper(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
objectMapper.configure(org.codehaus.jackson.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
}
}
If you are using Jettison you can register a custom XmlAdapter:
public class LongAdapter extends XmlAdapter<String, Long> {
#Override
public String marshal(Long id) throws Exception {
if (id == null) {
return "";
}
return id.toString();
}
#Override
public Long unmarshal(String id) throws Exception {
return Long.parseLong(id);
}
}

TestCase issue in mocking

As i just started Mockito, I have below method that i want to test. In my YouTubeChannelImporter.java file there are both methods : readJsonFromUrl(String url) and readAll(rd)
public JSONObject readJsonFromUrl(String url) throws IOException,
JSONException {
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is,
Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
}
I started with some rough idea.Below is the sample test case.
#Test
public void readJsonFromUrl() throws IOException, JSONException {
String urlTest="http://google.com/api";
YouTubeChannelImporter mockYoutube = mock(YouTubeChannelImporter.class);
YouTubeChannelImporter tubeChannelImporter =new YouTubeChannelImporter();
// URL url=new URL(urlTest);
// InputStream inputStream = mock(InputStream.class);
// when(url.openStream()).thenReturn(inputStream);
BufferedReader rd=mock(BufferedReader.class);
when(mockYoutube.readAll(rd)).thenReturn("{\"kind\":\"you\"}");
String jsonText="{\"kind\":\"you\"}";
JSONObject object=new JSONObject(jsonText);
assertEquals("{\"kind\":\"you\"}",tubeChannelImporter.readJsonFromUrl(urlTest).toString());
}
My issue is when i will test the function readJsonFromUrl(String url) then readAll(rd) should not execute. Rather mock should be in action here. I am aware this issue is because tubeChannelImporter.readJsonFromUrl(urlTest).toString() . Looking for any other way to achieve my goal.
Thanks
You're mocking one instance of your class, and then executing another - as you noticed, this does not achieve the intended result.
I think the easiest way of testing your method is with spying ("partial mocking"). With this technique, you'll have an actual instance of your class with only a single method, readAll mocked out:
#Test
public void readJsonFromUrl() throws IOException, JSONException {
// Set up the spied instance:
YouTubeChannelImporter tubeChannelImporter = spy(new YouTubeChannelImporter());
doReturn("{\"kind\":\"you\"}").when(tubeChannelImporter).readAll(any(Reader.class));
// Test the execution
String urlTest="http://google.com/api";
String jsonText="{\"kind\":\"you\"}";
JSONObject object=new JSONObject(jsonText);
assertEquals("{\"kind\":\"you\"}",tubeChannelImporter.readJsonFromUrl(urlTest).toString());
}
Personally, for a test like this where you have to read a file and there's not much else going on, I would read an actual file rather than mock out a BufferedReader. Then you just have to Assert on the JSONObject output from the call to readJsonFromUrl().
Your problems stem from trying to test against the private method readAll(). Try to test only your public methods in your tests (e.g. readJsonFromUrl()) and you'll find you have to jump through less hoops in your test code.
If your class already implements an Interface, then just write tests against the Interface.
If you find that you have a lot of private methods, perhaps your class is responsible for doing too much work, so factor methods out into their own class(es). Then you can test them in isolation.
If you have a maven project, the place to put your test files, to read from, is in /src/test/resources

FreeMarker can't access properties of a javabean

According to the documentation, you should be able to pass a javabean to a FreeMarker template, and it will be able to access the getters of the bean. I've been trying to do this, but have not had any luck. Here's my code where I pass the bean to the template.
public class Hello extends HttpServlet {
public static final Logger LOGGER = Logger.getLogger(Hello.class.getName());
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File(this.getServletContext().getRealPath("/templates")));
cfg.setObjectWrapper(new DefaultObjectWrapper());
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
cfg.setIncompatibleImprovements(new Version(2, 3, 20)); // FreeMarker 2.3.20
final String name = req.getParameter("name");
// This works when model is a Map, but not when it is a bean
Model model = new Model();
model.setUsername(name);
Template template = cfg.getTemplate("hello.ftl");
template.process(model, resp.getWriter());
} catch (TemplateException ex) {
LOGGER.log(Level.SEVERE, "Unexpected template exception", ex);
resp.sendError(500);
}
}
private static class Model {
private String username;
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
}
When I try to access ${username} in a template, I get the following error.
The following has evaluated to null or missing:
==> username [in template "hello.ftl" at line 8, column 10]
Tip: If the failing expression is known to be legally null/missing... (snip)
The failing instruction (FTL stack trace):
----------
==> ${username} [in template "hello.ftl" at line 8, column 8]
----------
I can get the template to work correctly when I use a Map. I've tried explicitly wrapping the Model object with various TemplateModel wrappers, but nothing I try seems to work.
Any hints?
Model must be a public class for this to work.
Some other notes unrelated to the question: Use setServletContextForTemplateLoading instead setDirectoryForTemplateLoading, or else your app won't work if it's run from an unpacked .war. Also, of course you must not re-create the Configuration for each request, but I assume that's like that only for the sake of this example.