We are using spring oauth and there are several places where we need to use inheritance.
In the immediate case we are extending TokenEndpoint
public class MyTokenEndpoint extends TokenEndpoint {
//...
public ResponseEntity<OAuth2AccessToken> getAccessToken(
Principal principal,
MyParams myParams,
#RequestParam Map<String, String> allParams) {
// .. Stuff Happens
updateParamsWithStuff(allParams);
return super.getAccessToken(
principal, myParams.grantType(), allParams);
}
//...
}
Now what I want to test is if the map passed to super.getAcccessToken has been filled with Stuff. My simple way was to spy on the map passed in, but this relies on implemetation details and does not actually insure that stuff is in the map passed super.getAccessToken
We are using Mockito, I have seen comments that this will not work, and one that implies it may. Can this be done in any of the mocking frameworks?
See both answers on ( Can I mock a superclass's constructor with Mockito/Powermock?, the checked one says impossible, but given the discussion on the second answer I just had to try.)
After reading that I tried the following:
MyTokenEndpoint spyEndpoint = Mockito.spy(endpoint); //endpoint Set-up previously
Mockito.doAnswer(new Answer<ResponseEntity<OAuth2AccessToken>>() {
#Override
public ResponseEntity<OAuth2AccessToken>
answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Map<String, String> params = (Map<String, String>) args[2];
System.out.printf("%s\n", params.toString());
return new ResponseEntity<OAuth2AccessToken>(HttpStatus.ACCEPTED);
}
}).when(((TokenEndpoint) spyEndpoint))
.getAccessToken(any(Principal.class),
anyString(), (Map<String, String>) anyMap());
theResponse = spyEndpoint
.getAccessToken(principal,
myPrams,
currentMap);
But the code in answer never gets called.
Am I barking up the wrong tree?? Is this possible in any mocking framework?
Why do you need to mock? You are already extending the class--just override that method, examine the data passed in then forward the data to the parent.
Such a test can be easily written with JMockit:
#Test
public void mockCallToSuper(#Mocked final TokenEndpoint mockedBase)
{
final Principal principal = null; // or whatever
MyParams myParams = new MyParams();
Map<String, String> params = new HashMap<String, String>();
ResponseEntity<OAuth2AccessToken> accessToken =
new MyTokenEndpoint().getAccessToken(principal, myParams, params);
// asserts on "accessToken"
new Verifications() {{
Map<String, String> actualParams;
mockedBase.getAccessToken(
principal, (MyParams) any, actualParams = withCapture());
assertEquals("abc", actualParams.get("A"));
assertEquals("another item", actualParams.get("B2"));
}};
}
Related
The problem is that nothing is added to my cache. My class is much bigger so I provide here to minimum example that should reproduce the problem.
Let's say I have a dictionary class, which uses some initialService to return hashMap with initial values.
public class Dictionary() {
#Inject
private InitialService initialService;
private Map<String, String> map;
public Map<String, String> constructMap() {
HashMap<String, String> initialMap = initialService.getHashMap("initialKey", "initialValue");
return initialMap;
}
public void saveConstructedMap() {
map = constructMap();
}
public Map<String, String> getMap() {
return map;
}
}
Then I have a test with mockito. So firstly I save the map with method saveConstructedMap() then I get the map with getMap() and then I add there value.
I would expect the value to be there but the map is empty.
Even if I don't save it to new value but will do the put on getMap() so getMap().put(...)
public class DictionaryTest() {
#Mock
private InitialService initialService;
#InjectMocks
private Dictionary dictionary;
public void test() {
dictionary.saveConstructedMap();
HashMap<String, String> myMap = dictionary.getMap();
myMap.put("key","value");
assertTrue(myMap.containsKey("key")); //returns false (the entry is not added)
}
}
From what I understand the Mock just mocks the class so its empty inside, but #InjectMocks injects the specified mock and creates an object but in normal way (like I would do it with constructor for the Dictionary. So all the methods and fields should behave as in normal class, not test one. Did i misunderstand something here?)
Does anyone know what should i do to achieve what i want?
Of course i have initMocks(this) in the setUp() method which is annotated with #Before,
Actually, DictionaryTest can't be compiled, e.g. because of HashMap<String, String> myMap = dictionary.getMap(); line (should be Map<String, String>). Probably you've written it just for the question.
Nevertheless, the main idea of mock testing is to provide a custom implementation of mocked class' methods. In this case, you should do it for the getHashMap method of InitialService mock. The example is below:
Map<String, String> initialMap = new HashMap<>();
initialMap.put(initialKey, initialValue);
Mockito.when(initialService.getHashMap("initialKey", "initialValue")).thenReturn(initialMap);
If you don't do that, Mockito will set the default value as a result of the method (in this case, it would be null):
By default, for all methods that return a value, a mock will return either null, a primitive/primitive wrapper value, or an empty collection, as appropriate.
Another approach is to make a partial mock and use real implementations of its methods where needed. But don't take advantage of it.
I'm creating a unit test for the below Java code which gets data from a database and, via a lambda, maps the data retrieved into a list:
List<Pair<String, String>> list = jdbcTemplate.query(MY_QUERY, (rs, rowNum) -> {
String code = rs.getString(1);
String name = rs.getString(2);
return new Pair<String, String>(code, name);
});
It's part of a Spring framework service class; the unit test is run via SpringJUnit4ClassRunner.
I've used Mockito to mock the jdbcTemplate object (of type NamedParameterJdbcTemplate).
I'm trying to mock the result of the jdbcTemplate. Looking at the method call, it looks like I need to mock this method in the NamedParameterJdbcTemplate class:
query(String sql, RowMapper<T> rowMapper)
I have tried this:
List<Pair<String, String>> pairList = ...;
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(RowMapper.class))).thenReturn(pairList);
... but when I run the unit test, the "list" variable is always null after the line of code has been passed, as if the mock hasn't been triggered to return my value.
The Mockito object is definitely being injected into the class.
Printing the mock's invocactions displays this:
[Mockito] Interactions of: Mock for NamedParameterJdbcTemplate, hashCode: <n>
1. namedParameterJdbcTemplate.query("query", my.package.MyClass$$Lambda$114/1274225913#3e134896);
Is there anything I'm obviously doing wrong? Thanks in advance for any assistance.
try Mockito.any(Function.class)
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(Function.class))).thenReturn(pairList);
I moved the mock's configuration to where it's created:
#Bean(name = "jdbcTemplate")
public NamedParameterJdbcTemplate jdbcTemplate() {
NamedParameterJdbcTemplate jdbcTemplate = Mockito.mock(NamedParameterJdbcTemplate.class);
Pair<String, String> pair = new Pair<String, String>(CODE, NAME);
List<Pair<String, String>> pairList = new ArrayList<Pair<String, String>>();
pairList.add(pair);
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(RowMapper.class))).thenReturn(pairList);
return jdbcTemplate;
}
It works now.
I'm trying to map a Supplier Bean to an Azure function using Spring Cloud Function 2.0, but I need to extend AzureSpringBootRequestHandler, which seems to only support functions with an input parameter and a return value. class AzureSpringBootRequestHandler has two type parameters: input and output, and AzureSpringBootRequestHandler.handleRequest() also expects the input parameter.
#Bean
public Supplier<List<String>> foo() {
return () -> Arrays.asList("foo1", "foo2");
}
/////
class FooFunction extends AzureSpringBootRequestHandler<Void, List<String>> {
#FunctionName("foo")
List<String> foo(#HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
ExecutionContext context) {
return handleRequest(null, context);
}
}
The code above causes NPE at reactor.core.publisher.FluxJust.(FluxJust.java:60)
Changing the #Bean return type to Function<Void, List<String>> causes IllegalStateException "No function defined with name=foo" at AzureSpringFunctionInitializer.lookup
Adding a dummy int parameter works.
P.S Ideally I don't even need the return value so instead of Supplier I would make it a Runnable, but this seems completely unsupported.
Any help would be appreciated.
Support for supplier and consumer is added in Spring Cloud Function 3.0.0. This is currently still a milestone.
More information this change.
I solved the issue, using Spring Cloud Function 2.x, by changing the signature of AzureSpringBootRequestHandler to use Optional as follows:
public class SomeFunction extends AzureSpringBootRequestHandler<Optional<?>, List<Foo>> {
#FunctionName("some-function")
public List<Device> execute(#HttpTrigger(name = "req",
methods = {HttpMethod.GET},
authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Void> request,
ExecutionContext context) {
return handleRequest(Optional.empty(), context);
}
}
You'll also have to change the type of your bean to match this:
#Bean(name="some-function")
public Function<Optional<?>, List<Device>> someFunction() {
return v -> fooService.bar();
}
I'm working on a project where I need to call many different services and wanted to abstract out as much of the common logic as I can. The kicker is that I also want to return custom objects instead of something such as json. As I designed a way of doing this, I arrived at a paradigm that reminds me of a Strategy Pattern, but I don't quite think it fits. I'm wondering if there are any design flaws or dangers in how I've done this.
Basically I've created an abstract class (ServiceCall) that holds the common logic for calling a service (have an internet client and get a json response from the desired service). This is all done with the public method call(Map<String, String> params, Map<String, String> headers). The abstract class also defines two abstrach methods: createCustomDTO(Map<String, String> params, Map<String, String> headers) and parseResponseToObject(String json). I'll explain the purpose of these in just a second.
Each call to a different service will be created with a class that extends ServiceCall and creates an implementation of the abstract methods. createCustomDTO will create a custom object that contains all the information needed to call the service (url, and headers). parseResponseToObject will take a json response and turn it into the java object I want to use later in my code.
Here is a simple implementation of what I did
ServiceCall
public abstract class ServiceCall {
protected abstract Object parseResponseToObject(String json);
protected abstract CustomServiceDTO createDTO(Map<String, String> keys,
Map<String, String> headers);
public Object call(Map<String, String> params, Map<String, String> headers) {
// create and configure a CustomServiceDTO to call services with
CustomServiceDTO dto = createDTO(params, headers);
try {
// make the service request
String json = getServiceResponse(dto);
catch (Exception e) {
return new CustomServiceError(e);
}
// parse the response into the desired java object
Object response = parseResponseToObject(json);
return response;
}
private String getServiceResponse(CustomServiceDTO dto) {
// use common logic to call the service using the information provided
// by the dto
String dummyResponse = "{\"prop\":\"value\"}";
return dummyResponse;
}
}
SampleImplementation
public class AddressCall extends ServiceCall {
#Override
protected Object parseResponseToObject(String json) {
return new Address(json);
}
#Override
protected CustomServiceDTO createDTO(Map<String, String> keys,
Map<String, String> headers) {
CustomServiceDTO dto = new CustomServiceDTO();
dto.setUrl("www.getMyDummyAddress.com/" + keys.get(0) + "=" + keys.get(1));
dto.setHeaders(headers);
return dto;
}
}
The main drawback I see to this is that never directly calling createCustomDTO and parseResponseToObject is a little strange.
The main advantage for me is the ease of use and having my responses returned as java objects.
What I really want to know is are there any other concerns or drawbacks to this paradigm? It's very nice in the code, but I admit it seems a bit different from how java is normally used.
This is not different from how Java is normally used, this is called a Template Method design pattern.
It's pretty common, except for the use of Object, which is better replaced by a generic type.
I'm trying to set up unit testing. I'm using Struts2 and Liferay 6.1.
I'm getting the below error
java.lang.NullPointerException
at com.liferay.portal.util.PortalUtil.getCompany(PortalUtil.java:305)
at com.mycomp.portlet.action.BasePortletAction.setupSiteAgent(BasePortletAction.java:1169)
This is because PortalUtil.getPortal() returns null. Is there a way I could somehow create a mock portal? There is no MockPortal class. I have found something called MockPortalContext but I'm not sure how to make use of it.
This is my code so far
BaseTestCase.java
public abstract class BaseTestCase extends TestCase {
private Dispatcher dispatcher;
protected ActionProxy proxy;
private static MockServletContext servletContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
public BaseTestCase(String name) {
super(name);
}
#SuppressWarnings("unchecked")
protected <T>T createAction(Class<T> theClass, String namespace, String actionName, String methodName, HashMap<String, Object> actionContextMap, HashMap<String, Object> parameterMap) throws Exception {
proxy = dispatcher.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, actionName, methodName, new HashMap<String, Object>(), true, true);
for (String key : actionContextMap.keySet()) {
proxy.getInvocation().getInvocationContext().put(key, actionContextMap.get(key));
}
proxy.getInvocation().getInvocationContext().setParameters(parameterMap);
proxy.setExecuteResult(true);
ServletActionContext.setContext(proxy.getInvocation().getInvocationContext());
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
ServletActionContext.setRequest(request);
ServletActionContext.setResponse(response);
ServletActionContext.setServletContext(servletContext);
return (T) proxy.getAction();
}
protected void setUp() throws Exception {
final String[] config = new String[]{"struts.xml", "mockApplicationContext.xml"};
servletContext = new MockServletContext();
final XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setServletContext(servletContext);
appContext.setConfigLocations(config);
appContext.refresh();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appContext);
HashMap<String, String> params = new HashMap<String, String>();
params.put("actionPackages", "com.mycomp.portlet.action");
dispatcher = new Dispatcher(servletContext, params);
dispatcher.init();
Dispatcher.setInstance(dispatcher);
}
}
ActionTest.java
public class ActionTest extends BaseTestCase {
private Map<String, Object> contextMap;
private Map<String, Object> parameterMap;
private MockPortletRequest portletRequest;
private final String REQUEST_LOCALE = "request_locale";
public ActionTest(String name) {
super(name);
}
public void testShowDetail() throws Exception {
init();
parameterMap = new HashMap<String, Object>();
parameterMap.put(REQUEST_LOCALE, "en_GB");
#SuppressWarnings("unused")
PortletAction lspa = createAction(PortletAction.class,
"/view",
"myAction",
"myAction",
(HashMap<String, Object>)contextMap,
(HashMap<String, Object>)parameterMap);
String result = proxy.execute();
System.out.println(result);
}
private void init() {
portletRequest = new MockPortletRequest();
contextMap = new HashMap<String, Object>();
contextMap.put(PortletActionConstants.REQUEST, portletRequest);
}
}
The Spring documentation says creating a MockPortletRequst() with the no-arg constructor creates it with a default MockPortletContext and MockPortalContext so I don't know why it's null.
Use Powermock or jMockit to mock the static method call PortalUtil.getPortal()
Technically the answer has already been given by John B. I'd like to add a philosophical angle.
IMHO mocking a complex environment like a portal doesn't buy a lot, especially when we speak about unit testing. You'll gain more insight into your code by minimizing contact with any complex API and environment (not just a portal), rather decouple from that APIs.
One solution is to have very simple wiring in portlet classes (and code-review this) while extracting testable code into its own - fully tested - classes that don't call out to the external API, rather get their context passed in.
This would leave you with some very simple code that's not unit-tested, but in addition to the code-review you can (and should) add some integration/smoke tests that actually work in the full environment.
Sometimes a simple solution will be to quickly mock portal classes (or other external classes), but I don't see this as the preferred solution. As soon as you start writing significant setup code to prepare the environment, you've gained nothing when your test runs. And if it fails, you'll have to check it in the real environment anyways to see if your setup was accurate.
Sorry if this is bad news - IMHO it's inherent when you have any given API that has not been built with being replaceable in unit tests. And with my unwillingness to routinely have large setup routines in unit tests. I'd not call them unit tests, if this happens frequently - rather break down the (too complex) unit into more smaller ones. Or accept code-review for simple wiring (adaptation) code between two different APIs.