I am trying to test my Play Application controller, but am struggling to find away to have the test return both session data while utilising an instance of the controller.
public class HomeControllerTest extends WithApplication {
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.configure("play.http.router", "router.Routes")
.build();
}
#Test
public void testGameChoiceHvH() {
Map form = new HashMap<String, String>();
form.put("gameType", "0");
HomeController homeController = new HomeController();
Result result = invokeWithContext(fakeRequest().bodyForm(form),
() -> homeController.chooseGame());
assertEquals(SEE_OTHER, result.status());
assertEquals("/play", result.header("Location").get());
assertFalse(result.session().isEmpty());
String gameId = result.session().get("game_id");
assertTrue(homeController.getGame(gameId).getCurrentPlayer() instanceof Human);
}
}
The final assertion here is simulating taking the gameId stored in the session and using it retrieve the game instance, created in the controller action and stored in a Map within the controller instance. The issue is that by using invokeWithContext, the result does not contain the Cookie object at all, so it cannot be retrieved.
The alternative method I have found to create a post request is the following:
public class HomeControllerTest extends WithApplication {
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.configure("play.http.router", "router.Routes")
.build();
}
#Test
public void testGameChoiceHvH() {
Map form = new HashMap<String, String>();
form.put("gameType", "0");
HomeController homeController = new HomeController();
Result result = route(fakeRequest(routes.HomeController.chooseGame()).bodyForm(form));
assertEquals(SEE_OTHER, result.status());
assertEquals("/play", result.header("Location").get());
assertFalse(result.session().isEmpty());
String gameId = result.session().get("game_id");
assertTrue(homeController.getGame(gameId).getCurrentPlayer() instanceof Human);
}
}
However, this obviously means that the final assertion is looking at a new instance of the HomeController, not the one used by the route function, so as such, the Map is empty.
For clarity, here is the relevant controller code:
public class HomeController extends Controller {
private WebInterface ui = new WebInterface();
private Map<String, Board> boardMap = new HashMap<>();
private Map<String, Game> gameMap = new HashMap<>();
public Game getGame(String gameId) {
return gameMap.get(gameId);
}
public Result chooseGame() {
Map<String, String[]> request = request().body().asFormUrlEncoded();
Board board = new Board();
Game game = new Game(new PlayerFactory(ui).create(GameType.values()[Integer.valueOf(request.get("gameType")[0])]));
boardMap.put(Integer.toString(board.hashCode()), board);
gameMap.put(Integer.toString(game.hashCode()), game);
session("game_id", Integer.toString(game.hashCode()));
session("board_id", Integer.toString(board.hashCode()));
return redirect("/play");
}
Any help would be much appreciated.
So, after too long looking for a solution to this, I found the answer in the source code:
/**
* Calls a Callable which invokes a Controller or some other method with a Context
*/
public static <V> V invokeWithContext(RequestBuilder requestBuilder, Callable<V> callable) {
try {
Context.current.set(new Context(requestBuilder));
return callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
Context.current.remove();
}
}
Based on this, information, it is now obvious why invokeWithContext doesn't expose the context after it is run. So as a quick and dirty implementation of a solution:
#Test
public void testGameChoiceHvH() {
Map form = new HashMap<String, String>();
form.put("gameType", "0");
HomeController homeController = new HomeController();
Http.RequestBuilder request = fakeRequest(routes.HomeController.chooseGame()).bodyForm(form);
try {
Http.Context.current.set(new Http.Context(request));
homeController.chooseGame();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
assertFalse(Http.Context.current().session().isEmpty());
String gameId = Http.Context.current().session().get("game_id");
assertTrue(homeController.getGame(gameId).getCurrentPlayer() instanceof DelayedComputer);
Http.Context.current.remove();
}
}
This exposes both the session, and the homeController instance, so the assertions can both be tested.
Related
I have the following service class:
#Singleton
public class QuotesLoaderBean {
Properties quotes;
Properties names;
#Inject
public QuoteRepository repo;
public QuotesLoaderBean() {
}
#PostConstruct
public void init() {
InputStream quotesInput = this.getClass().getClassLoader().getResourceAsStream("quotes.properties");
InputStream namesInput = this.getClass().getClassLoader().getResourceAsStream("names.properties");
quotes = new Properties();
names = new Properties();
try {
quotes.load(quotesInput);
names.load(namesInput);
} catch (IOException ex) {
Logger.getLogger(QuotesLoaderBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
public Citation createCitation(String quote) {
Citation citation = new Citation();
citation.setQuote(quote);
citation.setWho(getName());
repo.save();
return citation;
}
public Citation getCitation() {
Citation citation = new Citation();
citation.setQuote(getQuote());
citation.setWho(getName());
return citation;
}
public String getQuote() {
Enumeration keys = quotes.propertyNames();
int elementNumber = new Random().nextInt(quotes.keySet().size());
return quotes.getProperty(getElement(keys, elementNumber));
}
public String getName() {
Enumeration keys = names.propertyNames();
int elementNumber = new Random().nextInt(names.keySet().size());
return names.getProperty(getElement(keys, elementNumber));
}
private String getElement(Enumeration keys, int elementNumber) {
int i = 0;
while (keys.hasMoreElements()) {
if (i == elementNumber) {
return (String) keys.nextElement();
} else {
i++;
keys.nextElement();
}
}
return null;
}
}
The Repository class is very simple for test purposes:
#Singleton
public class QuoteRepository {
public String save() {
Gson gson = new GsonBuilder().create();
return "Saved...";
}
}
When I test the createCitation method I always get a NullPointerException but I cant figure out why. Something is not working with Injection. I also have a api class that is annotated with #Stateless and there I can easily inject the service class with with the #Inject annotation.
When I test the createCitation method I always get a NullPointerException
You can't simply test your application, because you delegated the responsibility of objects creation to the container which in unit tests (I assume you use it) does not exist.
public Citation createCitation(String quote) {
Citation citation = new Citation();
citation.setQuote(quote);
citation.setWho(getName());
repo.save(); // repo isn't initialized
return citation;
}
If you want to test your code, mock repo object or use integration test.
I am developing application which having Parse Platform. To fetch data I am calling ParseCloud.callFunctionInBackground function.
I have registered the Parse and its sub class into the Application class like below :
public class App extends Application {
#Override
public void onCreate(){
super.onCreate();
Parse.setLogLevel(Parse.LOG_LEVEL_VERBOSE);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.networkInterceptors().add(httpLoggingInterceptor);
ParseObject.registerSubclass(ParseMessage.class);
Parse.initialize(new Parse.Configuration.Builder(this)
.applicationId("KEY")
.server("URL")
.build());
}
}
I have below model class which extends ParseObject :
#ParseClassName("ParseMessage")
public class ParseMessage extends ParseObject {
// Ensure that your subclass has a public default constructor
public ParseMessage() {
super();
}
public ParsePhoto getPhotos() {
return (ParsePhoto) getParseObject("photos");
}
public void setPhotos(ParsePhoto value) {
put("photos", value);
}
public String getCaption() {
return getString("caption");
}
public void setCaption(String value) {
put("caption", value);
}
}
When I calling this below method from my Fragment :
HashMap<String, Object> params = new HashMap<String, Object>();
ParseCloud.callFunctionInBackground("MY_METHOD", params, new FunctionCallback<ArrayList<ParseMessage>>() {
public void done(ArrayList<ParseMessage> mapObject, ParseException e) {
if (e == null) {
ParseMessage object = mapObject.get(i);
}
} else {
}
}
});
But I am getting below exception :
java.lang.ClassCastException: com.parse.ParseObject cannot be cast to
com.example.ParseMessage
I already searched lots of thins from Google and Stackoverflow, but I did not get any solutions of it. Can anyone help me into this as I already spend a lot of time on this. Below response which I am getting from Parse :
The info you have provided is not very concrete, but from the debugger screen, it looks like you are trying to convert ParsePhoto into ParseMessage. ParsePhoto is subclass of ParseObject, and I believe this is causing the issue.
I am working on a project in which I need to have synchronous and asynchronous method of my java client. Some customer will call synchronous and some customer will call asynchronous method of my java client depending on there requirement.
Below is my java client which has synchronous and asynchronous methods -
public class TestingClient implements IClient {
private ExecutorService service = Executors.newFixedThreadPool(10);
private RestTemplate restTemplate = new RestTemplate();
// for synchronous
#Override
public String executeSync(ClientKey keys) {
String response = null;
try {
Future<String> handle = executeAsync(keys);
response = handle.get(keys.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
} catch (Exception e) {
}
return response;
}
// for asynchronous
#Override
public Future<String> executeAsync(ClientKey keys) {
Future<String> future = null;
try {
ClientTask ClientTask = new ClientTask(keys, restTemplate);
future = service.submit(ClientTask);
} catch (Exception ex) {
}
return future;
}
}
And now below is my ClientTask class which implements Callable interface and I am passing around the dependency using DI pattern in the ClientTask class. In the call method, I am just making a URL basis on machineIPAddress and using the ClientKeys which is passed to ClientTask class and then hit the server using RestTemplate and get the response back -
class ClientTask implements Callable<String> {
private ClientKey cKeys;
private RestTemplate restTemplate;
public ClientTask(ClientKey cKeys, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.cKeys = cKeys;
}
#Override
public String call() throws Exception {
// .. some code here
String url = generateURL("machineIPAddress");
String response = restTemplate.getForObject(url, String.class);
return response;
}
// is this method thread safe and the way I am using `cKeys` variable here is also thread safe?
private String generateURL(final String hostIPAdress) throws Exception {
StringBuffer url = new StringBuffer();
url.append("http://" + hostIPAdress + ":8087/user?user_id=" + cKeys.getUserId() + "&client_id="
+ cKeys.getClientId());
final Map<String, String> paramMap = cKeys.getParameterMap();
Set<Entry<String, String>> params = paramMap.entrySet();
for (Entry<String, String> e : params) {
url.append("&" + e.getKey());
url.append("=" + e.getValue());
}
return url.toString();
}
}
And below is my ClientKey class using Builder patter which customer will use to make the input parameters to pass to the TestingClient -
public final class ClientKey {
private final long userId;
private final int clientId;
private final long timeout;
private final boolean testFlag;
private final Map<String, String> parameterMap;
private ClientKey(Builder builder) {
this.userId = builder.userId;
this.clientId = builder.clientId;
this.remoteFlag = builder.remoteFlag;
this.testFlag = builder.testFlag;
this.parameterMap = builder.parameterMap;
this.timeout = builder.timeout;
}
public static class Builder {
protected final long userId;
protected final int clientId;
protected long timeout = 200L;
protected boolean remoteFlag = false;
protected boolean testFlag = true;
protected Map<String, String> parameterMap;
public Builder(long userId, int clientId) {
this.userId = userId;
this.clientId = clientId;
}
public Builder parameterMap(Map<String, String> parameterMap) {
this.parameterMap = parameterMap;
return this;
}
public Builder remoteFlag(boolean remoteFlag) {
this.remoteFlag = remoteFlag;
return this;
}
public Builder testFlag(boolean testFlag) {
this.testFlag = testFlag;
return this;
}
public Builder addTimeout(long timeout) {
this.timeout = timeout;
return this;
}
public ClientKey build() {
return new ClientKey(this);
}
}
public long getUserId() {
return userId;
}
public int getClientId() {
return clientId;
}
public long getTimeout() {
return timeout;
}
public Map<String, String> getParameterMap() {
return parameterMap;
public boolean istestFlag() {
return testFlag;
}
}
Is my above code thread safe as I am using ClientKey variables in ClientTask class in multithreaded environment so not sure what will happen if another thread tries to make ClientKey variable while making a call to TestingClient synchronous method -
Because customer will be making a call to us with the use of below code and they can call us from there Multithreaded application as well -
IClient testClient = ClientFactory.getInstance();
Map<String, String> testMap = new LinkedHashMap<String, String>();
testMap.put("hello", "world");
ClientKey keys = new ClientKey.Builder(12345L, 200).addTimeout(2000L).parameterMap(testMap).build();
String response = testClient.executeSync(keys);
So just trying to understand whether my above code will be thread safe or not as they can pass multiple values to my TestingClient class from multiple threads. I am having a feeling that my ClientKey class is not thread safe because of parameterMap but not sure.
And also do I need StringBuffer here or StringBuilder will be fine as StringBuilder is faster than StringBuffer because it's not synchronized.
Can anyone help me with this?
The parameter ClientKey keys is given, so I assume is always different.
I don't see any synchronization issues with your code, I'll explain:
ClientTask ClientTask = new ClientTask(keys, restTemplate);
future = service.submit(ClientTask);
Creating a ClientTask object from inside the method, which is not shared among threads.
Using service.submit, whih returns a Future object
The ClientTask object read the keys only inside the method generateURL, but, as I said before, the ClientKeys object is given as a parameter, so you are good as long as this object is not being shared.
In summary, the thread-safeness of your code depends on ExecutorService and Future being thread safe.
Update: Clarification for as long as this object is not being shared
ClientKeys keys;
add keys to #keys
.. code
executeAsync(.., keys)
... code
add keys to #keys
add keys to #keys
executeAsync(.., keys)
executeAsync(.., keys)
add keys to #keys
... code
add keys to #keys
executeAsync(.., keys)
This is (more and less) what I meant is sharing. keys is being used in several threads due to the calls to executeAsync(). In this case, some threads are reading keys, and others are writing data to it, causing whats is ussualy called a race condition.
Update 2: The StringBuffer object is local to (aka is in the scope of) generateURL, there's no need to synchronize it.
I have a DTO, which looks a bit like this:
class Response {
Long id;
Locale locale;
Map<Integer,QuestionResponse> questionResponses=new HashMap<Integer,QuestionResponse>();
...
}
But I'm having trouble mapping a ColumnConfig to the value property of a questionResponses map entry. For example, I want something like this:
beanModel.get("questionResponses[15].value")
I can see from the get method in BeanModelData that I should be able to get a property of a Map but can't figure out the syntax. Any help would be really appreciated.
One solution is to use a DataReader to map your Response to a new Model
final ListLoader<BaseListLoadResult<BeanModel>> loader = new BaseListLoader<BaseListLoadResult<BeanModel>>(
proxy, new MyBeanModelReader());
loader.load();
new ListStore<BeanModel>(loader); //TODO
public class MyBeanModelReader implements DataReader<List<BeanModel>> {
private BeanModelReader reader = new BeanModelReader();
public boolean isFactoryForEachBean() {
return reader.isFactoryForEachBean();
}
public List<BeanModel> read(Object loadConfig, Object data) {
List<BeanModel> newModelsData = new ArrayList<BeanModel>();
ListLoadResult<ModelData> models = reader.read(loadConfig, data);
List<ModelData> modelsData = models.getData();
for (ModelData modelData : modelsData) {
BeanModel model = (BeanModel) modelData;
Response response = (Response) model.getBean();
model.set("id", response.getId());
model.set("locale", response.getLocale());
model.set("QuestionResponse15", response.getQuestionResponse().get(...)); //retrieve the QR you want
newModelsData.add(model);
}
return newModelsData;
}
public void setFactoryForEachBean(boolean factoryForEachBean) {
reader.setFactoryForEachBean(factoryForEachBean);
}
}
I'm currently writing a Spring MVC-based webapp.
Rather than writing one test for every annotated method, I would like to benefit from Parameterized JUnit runner.
Finally, I got it almost working, although I had to change all primitive arguments to their wrapper counterpart in my controller methods (and then manually do the sanity checks on null refs).
If it can help, here is the code (this also depends on Guava):
#RunWith(Parameterized.class)
public class MyControllerMappingTest {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MyController mockedController;
private AnnotationMethodHandlerAdapter annotationHandlerAdapter;
private final String httpMethod;
private final String uri;
private final String controllerMethod;
private final Class<?>[] parameterTypes;
private final Object[] parameterValues;
#Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
mockedController = mock(MyController.class);
annotationHandlerAdapter = new AnnotationMethodHandlerAdapter();
}
#Parameters
public static Collection<Object[]> requestMappings() {
return asList(new Object[][] {
{"GET", "/my/uri/0", "index", arguments(new MethodArgument(Integer.class, 0))}
});
}
private static List<MethodArgument> arguments(MethodArgument... arguments) {
return asList(arguments);
}
public MyControllerMappingTest(String httpMethod, String uri, String controllerMethod, List<MethodArgument> additionalParameters) {
this.httpMethod = httpMethod;
this.uri = uri;
this.controllerMethod = controllerMethod;
this.parameterTypes = new Class<?>[additionalParameters.size()];
initializeParameterTypes(additionalParameters);
this.parameterValues = newArrayList(transform(additionalParameters, valueExtractor())).toArray();
}
private void initializeParameterTypes(List<MethodArgument> additionalParameters) {
Iterable<Class<?>> classes = transform(additionalParameters, typeExtractor());
int i = 0;
for (Class<?> parameterClass : classes) {
parameterTypes[i++] = parameterClass;
}
}
#Test
public void when_matching_mapping_constraints_then_controller_method_automatically_called() throws Exception {
request.setMethod(httpMethod);
request.setRequestURI(uri);
annotationHandlerAdapter.handle(request, response, mockedController);
Method method = MyController.class.getMethod(controllerMethod, parameterTypes);
method.invoke(verify(mockedController), parameterValues);
}
}
with the custom class MethodArgument that follows:
public class MethodArgument {
private final Class<?> type;
private final Object value;
public MethodArgument(final Class<?> type, final Object value) {
this.type = type;
this.value = value;
}
public Object getValue() {
return value;
}
public Class<?> getType() {
return type;
}
public static Function<MethodArgument, Class<?>> typeExtractor() {
return new Function<MethodArgument, Class<?>>() {
#Override
public Class<?> apply(MethodArgument argument) {
return argument.getType();
}
};
}
public static Function<MethodArgument, Object> valueExtractor() {
return new Function<MethodArgument, Object>() {
#Override
public Object apply(MethodArgument argument) {
return argument.getValue();
}
};
}
}
So, I'm almost there, the only test case here works because of Java Integer cache, and the Integer instance is therefore the same throughout the call chain... This however doesn't work with custom objects, I always end up with an InvocationTargetException (cause: "Argument(s) are different!")...
The types are correct but the passed instances are not identical to the ones set in the #Parameters method.
Any idea how to work around this?
Hold your horses!
SpringSource is baking a spring-test-mvc module :
https://github.com/SpringSource/spring-test-mvc
It would be nice if instead of providing the example that works, you could provide the one that doesn't, and provide the stacktrace as well.
I quickly checked Google, it seems that Mockito doesn't handle well reflection on spy objects.
If you really wanna go along that road, there might be another way: providing the expected called method as part of your parameterized data, not by providing reflection data, but by actually calling the mock from there.
I'm writing that without any IDE at hand, so there might be compile errors, but you'll get the idea:
#RunWith(Parameterized.class)
public class MyControllerMappingTest {
public interface VerifyCall<T> {
void on(T controller);
}
#Parameters
public static Collection<Object[]> requestMappings() {
Object[][] testCases = {
{"GET", "/my/uri/0", new VerifyCall<MyController>() {
#Override
public void on(MyController controller) {
controller.index(0);
}
}}
};
return asList(testCases);
}
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MyController mockedController;
private AnnotationMethodHandlerAdapter annotationHandlerAdapter;
private final String httpMethod;
private final String uri;
private final VerifyCall<MyController> verifyCall;
public MyControllerMappingTest(String httpMethod, String uri, VerifyCall<MyController> verifyCall) {
this.httpMethod = httpMethod;
this.uri = uri;
this.verifyCall = verifyCall;
}
#Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
mockedController = mock(MyController.class);
annotationHandlerAdapter = new AnnotationMethodHandlerAdapter();
}
#Test
public void when_matching_mapping_constraints_then_controller_method_automatically_called() throws Exception {
request.setMethod(httpMethod);
request.setRequestURI(uri);
annotationHandlerAdapter.handle(request, response, mockedController);
verifyCall.on(verify(mockedController));
}
}
Of course, having Java Lambas would help making this more readable.
You could also use FunkyJFunctional :
#RunWith(Parameterized.class)
public class MyControllerMappingTest {
#Parameters
public static Collection<Object[]> requestMappings() {
class IndexZero extends FF<MyController, Void> {{ in.index(0); }}
Object[][] testCases = { //
{"GET", "/my/uri/0", withF(IndexZero.clas)}
};
return asList(testCases);
}
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MyController mockedController;
private AnnotationMethodHandlerAdapter annotationHandlerAdapter;
private final String httpMethod;
private final String uri;
private final Function<MyController, Void> verifyCall;
public MyControllerMappingTest(String httpMethod, String uri, Function<MyController, Void> verifyCall) {
this.httpMethod = httpMethod;
this.uri = uri;
this.verifyCall = verifyCall;
}
#Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
mockedController = mock(MyController.class);
annotationHandlerAdapter = new AnnotationMethodHandlerAdapter();
}
#Test
public void when_matching_mapping_constraints_then_controller_method_automatically_called() throws Exception {
request.setMethod(httpMethod);
request.setRequestURI(uri);
annotationHandlerAdapter.handle(request, response, mockedController);
verifyCall.apply(verify(mockedController));
}
}
A few side notes:
For the sake of readability, it's a good practice to put your static members first in your class. Instance methods (setup()) should also go after the constructor.
Array syntax:
Instead of this syntax:
return asList(new Object[][] {
{},
{}
};
I find this syntax to be more readable:
Object[][] testCases = {
{},
{}
};
return asList(testCases);