Im refactoring some unit tests. Basically, i ve found that unit tests of different clients implement a bundle of methods such as: createClientWithNullResponse, createClientWithSuccessResponse, etc.
I was wondering if its possible in Java to implement a generic solution to this, since this methods are repeated over and over in hundreds of unit classes, changing only the method signature.
But, there is a tricky. See a method example:
/**
* configures the client to return a succesful response
* #return a client configured to return a succesful response
*/
private Client1 configureClientWithSuccesfulResponse()
{
client = new Client1()
{
public CommonClientResponse processRequest( CommonsClientRequest commonsClientRequest )
{
CommonClientResponse commonClientResponse = new CommonClientResponse();
commonClientResponse.setResponse( new Client1Response() );
return commonClientResponse;
}
};
return client;
}
So, client2 will have the very same method except that signature have Client2, and the overrided method creates a new Client2Response, and the same with dozens of clients.
Additional information: processRequest is overrided to act as a mock, setting the response i wish for each method.
Client1 extends CommonsWS that extends of AbstractCommons, which is an abstract class but contains the implementation of processRequest method.
All in all, my idea is to create a Base class for all unit tests, with a bundle of generic methods where i can pass the class type, and then rewrite the processRequest for each one. Ive tried :
public class base <T extends AbstractCommonClient>{
private T configureClientWithNullResponse(Class <? extends AbstractCommonClient> clazz, Class< ? extends ClientResponse> clazz1)
{
try
{
return clazz.newInstance()
{
CommonClientResponse processRequest( CommonsClientRequest commonsClientRequest )
{
CommonClientResponse commonClientResponse = new CommonClientResponse();
commonClientResponse.setResponse( clazz1.newInstance() );
return commonClientResponse;
};
};
}
}
}
but it not even compile. Do you have any ideas of how i can begin implementing this?
As you are effectively trying to create an anonymous class whose type is unknown at runtime, have you considered invoking the compiler at runtime? I haven't used it much myself, but it may be worth investigating. You can invoke it by using
JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler();
Note that this will only work if the application is run on a system where JDK is install, as JRE (does not include javac).
This is a tricky question. I suggest create a Factory class that would return each type of client, and you provide the response and pass it to the factory. Something like:
public class ClientFactory {
public static createResponse(ClientResponse response) {
CommonClientResponse commonClientResponse = new CommonClientResponse();
commonClientResponse.setResponse(response);
return commonClientResponse;
}
public static Client1 createClient1(final ClientResponse response) {
return new Client1() {
public CommonClientResponse processRequest(CommonsClientRequest unused) {
return createResponse(response)
};
}
};
public static Client2 createClient2(final ClientResponse response) {
return new Client2() {
public CommonClientResponse processRequest(CommonsClientRequest unused) {
return createResponse(response)
};
}
};
..... // same for every type of Client
And you call it using:
factory.createClient1(new Client1Response());
There is still some duplication, but it helps. A little.
What do you think?
Related
I have a simple scenario in which am trying to verify some behavior when a method is called (i.e. that a certain method was called with given parameter, a function pointer in this scenario). Below are my classes:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
AppBootStrapper bootStrapper = context.getBean(AppBootStrapper.class);
bootStrapper.start();
}
}
#Component
public class AppBootStrapper {
private NetworkScanner networkScanner;
private PacketConsumer packetConsumer;
public AppBootStrapper(NetworkScanner networkScanner, PacketConsumer packetConsumer) {
this.networkScanner = networkScanner;
this.packetConsumer = packetConsumer;
}
public void start() {
networkScanner.addConsumer(packetConsumer::consumePacket);
networkScanner.startScan();
}
}
#Component
public class NetworkScanner {
private List<Consumer<String>> consumers = new ArrayList<>();
public void startScan(){
Executors.newSingleThreadExecutor().submit(() -> {
while(true) {
// do some scanning and get/parse packets
consumers.forEach(consumer -> consumer.accept("Package Data"));
}
});
}
public void addConsumer(Consumer<String> consumer) {
this.consumers.add(consumer);
}
}
#Component
public class PacketConsumer {
public void consumePacket(String packet) {
System.out.println("Packet received: " + packet);
}
}
#RunWith(JUnit4.class)
public class AppBootStrapperTest {
#Test
public void start() throws Exception {
NetworkScanner networkScanner = mock(NetworkScanner.class);
PacketConsumer packetConsumer = mock(PacketConsumer.class);
AppBootStrapper appBootStrapper = new AppBootStrapper(networkScanner, packetConsumer);
appBootStrapper.start();
verify(networkScanner).addConsumer(packetConsumer::consumePacket);
verify(networkScanner, times(1)).startScan();
}
}
I want to verify that bootStrapper did in fact do proper setup by registering the packet consumer(there might be other consumers registered later on, but this one is mandatory) and then called startScan. I get the following error message when I execute the test case:
Argument(s) are different! Wanted:
networkScanner bean.addConsumer(
com.spring.starter.AppBootStrapperTest$$Lambda$8/438123546#282308c3
);
-> at com.spring.starter.AppBootStrapperTest.start(AppBootStrapperTest.java:24)
Actual invocation has different arguments:
networkScanner bean.addConsumer(
com.spring.starter.AppBootStrapper$$Lambda$7/920446957#5dda14d0
);
-> at com.spring.starter.AppBootStrapper.start(AppBootStrapper.java:12)
From the exception, clearly the function pointers aren't the same.
Am I approaching this the right way? Is there something basic I am missing? I played around and had a consumer injected into PacketConsumer just to see if it made a different and that was OK, but I know that's certainly not the right way to go.
Any help, perspectives on this would be greatly appreciated.
Java doesn't have any concept of "function pointers"; when you see:
networkScanner.addConsumer(packetConsumer::consumePacket);
What Java actually compiles is (the equivalent of):
networkScanner.addConsumer(new Consumer<String>() {
#Override void accept(String packet) {
packetConsumer.consumePacket(packet);
}
});
This anonymous inner class happens to be called AppBootStrapper$$Lambda$7. Because it doesn't (and shouldn't) define an equals method, it will never be equal to the anonymous inner class that the compiler generates in your test, which happens to be called AppBootStrapperTest$$Lambda$8. This is regardless of the fact that the method bodies are the same, and are built in the same way from the same method reference.
If you generate the Consumer explicitly in your test and save it as a static final Consumer<String> field, then you can pass that reference in the test and compare it; at that point, reference equality should hold. This should work with a lambda expression or method reference just fine.
A more apt test would probably verify(packetConsumer, atLeastOnce()).consumePacket(...), as the contents of the lambda are an implementation detail and you're really more concerned about how your component collaborates with other components. The abstraction here should be at the consumePacket level, not at the addConsumer level.
See the comments and answer on this SO question.
I'm trying to build a simple (read-only) web app with GWT and RequestFactory, and I can't work out how to get rid of following warning:
warning: The domain type DDisplay is not default-instantiable. Calling RequestContext.create(DDisplayProxy.class) will cause a server error.
Add #SuppressWarnings("requestfactory") to dismiss.
The problem being, I have pasted #SuppressWarnings("requestfactory") above every possibly relevant class, interface and method, but I still get this message.
As my requestfactory is read-only, I'm not going to call RequestContext.create, so this is not a concern. It would just be nice to get rid of the warning (without creating a DDisplay locator class).
On the server side I have a domain object DDisplay, and a DAO, DDisplayService.
public class DDisplay {
public String getTitle () {
return "title";
}
}
and
public class DDisplayService {
public DDisplay getDisplayByUUID (String uuid) {
return new DDisplay ();
}
}
I have the following for RequestFactory:
#ProxyForName("com.foobar.server.display.DDisplay")
public interface DDisplayProxy extends EntityProxy {
String getTitle ();
}
and
public interface DisplayRequestFactory extends RequestFactory {
#ServiceName(
value="com.foobar.server.display.DDisplayService"
,locator="com.foobar.server.display.SpringServiceLocator"
)
public interface DisplayRequestContext extends RequestContext {
Request <DDisplayProxy> getDisplayByUUID (String id);
}
DisplayRequestContext display ();
}
Can anyone tell me where to put the #SuppressWarnings("requestfactory") to get rid of this error please? Or is there another way of doing this - do I just need to add a never-used Locator class?
thanks,
Jim
From reading the source where the error message come from, it appears that you can add this to your EntityProxy, DDisplayProxy. Something like this:
#SuppressWarnings("requestfactory")
#ProxyForName("com.foobar.server.display.DDisplay")
public interface DDisplayProxy extends EntityProxy {
String getTitle();
}
This from reading the source of com.google.web.bindery.requestfactory.apt.DomainChecker#visitType, which if currentTypeIsProxy is true and there is no locator, and the type isn't instatiable, the warning is emitted. From inside of state.warn(...) (which is given the proxy type element), it checks for the presence of the #SuppressWarnings annotation on that type.
I have a question about asynchronous method calls in java, especially about the response value of the async method.
The situation is the following:
The async method I want to call is..
public void getSpeed(IResponseListener listener) {
....
}
The interface of the listener is...
interface IResponseListener {
public void response(ResponseEvent event);
}
This method is called when the async method has a response value
My problem now is that the class ResponseEvent has an attribute response that can be of any type (boolean,float,String...)and in the implementation of the interface IResponseListener I have to cast the value...
IResponseListener listener = new IResponseListener {
public void response(ResponseEvent event) {
float f = (float)event.response;
}
}
Is this a good solution to handle this? I think the bad thing is that the response listener HAS to know the type of the response!
Is there a better solution to handle asynchronous calls that want to give a response even if the response can be of any type?
I think a lot of these answers are starting to look like this->
public interface Function<Args, Value>
{
public Value call(Args args);
}
Your return type doesn't matter--if it can return multiple types, then the "multiple types" are a type...might I suggest a type of JSON considering what you're looking at?
The reality is you can't expect your handler to know the type in advance so you need to specify that. Whether this is with the return type or the class is up to you.
I could easily see doing a class hierarchy:
public class ResponseString implements Function<Args, String>;
public class ResponseNumber implements Function<Args, Number>;
...
public class ResponseType implements Function<Args, Type>;
or simply creating a type that has all the information you need. The long and short is that the method can DEFINE what it expects for the types and you have the ability to extend them. Keep in mind that response could also be a Function which could be executed. There's nothing wrong with knowing what to DO with something and not knowing what it is ->
Example->
//Admittedly I'd probably have a "Procedure or VoidFunction interface as well".
public yourMethod(Function<String args, Function<String,?> handler)
{
String hello = "hello";
Function<String,?> function = handler.call(hello);
function.call(hello);
}
I hope this helps. Sometimes there's no reason to go this far, and sometimes there is. You don't know the type--it seems like maybe you're hoping someone else will provide it and this can do that for you while remaining strict.
EDIT:
the example of have for this in one framework is:
Applcation.openDialog(Dialog dialog, Callable<Boolean> onClose);
This returns true of the dialog cleans up and closes and false if not. I don't really care what happens here, I do care that it tells me yes, close it, or no don't.
Use Java generics:
interface IResponseListener<T> {
public void response(T response);
}
Then, in an anonymous class:
IResponseListener listener = new IResponseListener<Float> {
public void response(Float response) {
float f = response;
}
}
I don't know whether this is correct, but if you are going to handle the return value differently, why not overload the response method with different type of objects that you would expect. Just a suggestion..
interface InterfaceName{
void response(float responseVal);
void response(boolean responseVal);
...
}
I would have done as #nico_ekito says...Or use your existing solution. It is a problem that you don't know the result type.
Anyway, you could do some adjustments and let the ResponseEvent class do the casting for you.
ResponseListener.java
interface IResponseListener {
void response(ResponseEvent event);
}
ResponseEvent.java
public class ResponseEvent {
private Object response;
#SuppressWarnings("unchecked")
public <T> T getResponse() {
return (T)response;
}
public <T> void setResponse(T response) {
this.response = response;
}
}
Usage:
IResponseListener listener = new IResponseListener() {
public void response(ResponseEvent event) {
float f = event.getResponse();
}
};
Please note that you will get a ClassCastException if your type is something other than what you expect it to be.
When I make a call to fetch a list of TripImportSummaryProxy objects, I get back a list of:
com.schedgy.core.dao.filter.proxy.FilterProxyAutoBean_com_google_web_bindery_requestfactory_shared_impl_EntityProxyCategory_com_google_web_bindery_requestfactory_shared_impl_ValueProxyCategory_com_google_web_bindery_requestfactory_shared_impl_BaseProxyCategory.
#ProxyFor(value=TripImportSummary.class, locator=TripImportSummaryLocator.class)
public interface TripImportSummaryProxy extends MyBaseProxy {
// some setter/getters defined here
}
public interface TripImportSummaryRequestFactory extends RequestFactory, HasPaginationRequest<TripImportSummaryProxy> {
TripImportSummaryRequest request();
}
#Service(value=TripImportSummaryService.class, locator=MyServiceLocator.class)
public interface TripImportSummaryRequest extends RequestContext, PaginationRequest<TripImportSummaryProxy> {
}
#SkipInterfaceValidation
public interface HasPaginationRequest<T> extends RequestFactory {
PaginationRequest<T> request();
}
#ExtraTypes(FilterProxy.class)
#SkipInterfaceValidation
public interface PaginationRequest<T> extends RequestContext {
Request<List<T>> paginate(int offset, int limit, String sortColumn,
boolean isSortAscending, List<FilterProxy> filters);
Request<Integer> count(List<FilterProxy> list);
}
This is all executed via:
PaginationRequest<TripImportSummaryProxy> request = requestFactory.request();
request.paginate(offset, limit, sortColumn, isSortAscending, getFilters(request)).with(getPaths()).fire(new MyReceiver<List<TripImportSummaryProxy>>() {
#Override
public void onSuccess(List<TripImportSummaryProxy> response) {
// Response is a list of type that seems to extend from FilterProxy
}
});
FilterProxy is just a marker interface that various filter interfaces extend.
#ProxyFor(Object.class)
public interface FilterProxy extends ValueProxy {
}
I have about two dozen other requests working and its only failing on this one. I have verified that the server side service is correctly fetching and returning the right data. I have found that the TripImportSummaryLocator class is never instantiated even though it appears to be bound to the proxy type correctly and has a default constructor.
I was using GWT 2.4 rc1 and after upgrading to GWT 2.4 stable I am no longer seeing this problem.
I would like to know what's the best approach to test the method "pushEvent()" in the following class with a jUnit test.
My problem is, that the private method "callWebsite()" always requires a connection to the network. How can I avoid this requirement or refactor my class that I can test it without a connection to the network?
class MyClass {
public String pushEvent (Event event) {
//do something here
String url = constructURL (event); //construct the website url
String response = callWebsite (url);
return response;
}
private String callWebsite (String url) {
try {
URL requestURL = new URL (url);
HttpURLConnection connection = null;
connection = (HttpURLConnection) requestURL.openConnection ();
String responseMessage = responseParser.getResponseMessage (connection);
return responseMessage;
} catch (MalformedURLException e) {
e.printStackTrace ();
return e.getMessage ();
} catch (IOException e) {
e.printStackTrace ();
return e.getMessage ();
}
}
}
Stubbing
You'll need a test double (stub) to allow isolated, easy, unit testing. The following is non tested, but demonstrates the idea. The use of Dependency Injection will allow you to inject at test time, a test version of your HttpURLConnection.
public class MyClass()
{
private IHttpURLConnection httpUrlConnection;
public MyClass(IHttpURLConnection httpUrlConnection)
{
this.httpUrlConnection = httpUrlConnection;
}
public String pushEvent(Event event)
{
String url = constructURL(event);
String response = callWebsite(url);
return response;
}
}
Then you create a stub (sometimes referred to as a mock object) to be the stand in for the concrete instance.
class TestHttpURLConnection : IHttpURLConnection { /* Methods */ }
You'll also construct a concrete version, for your production code to use.
class MyHttpURLConnection : IHttpURLConnection { /* Methods */ }
Using your test class (an adapter) you are able to specifiy what should happen during your test. A mocking framework will enable you to do this with less code, or you can manually wire this up. The end result of this for your test is that you'll set your expectations for your test, for example, in this case you may set OpenConnection to return a true boolean (This is just an example by the way). Your test will then assert that when this value is true, the return value of your PushEvent method matches some expected result. I've not touched Java properly for a while, but here are some recommended mocking frameworks as specified by StackOverflow members.
Possible solution: You can extend this class, override callWebsite (you have to make it protected for this purpose) - and the override method write some stub method implementation.
Approaching things from a slightly different angle...
I'd worry less about testing this specific class. The code in it is extremely simple and, while a functional test to make sure it's working with a connection would be helpful, a unit level test "may" not be necessary.
Instead, I'd focus on testing the methods it calls that appear to actually do something. Specifically...
I'd test constructURL method from this line:
String url = constructURL (event);
making sure that it can construct a URL properly from different Events, and throws Exceptions when it should (possibly on an invalid Event or null).
And I'd test the method from the following line:
String responseMessage = responseParser.getResponseMessage (connection);
Possibly pulling out any "get information out of the connection" logic into one proc, and leaving only "parse said information" in the original one:
String responseMessage = responseParser.getResponseMessage(responseParser.getResponseFromConnection(connection));
or something along those lines.
The idea being to put any "must deal with external data sources" code in one method, and any code logic in separate methods that can be easily tested.
As an alternative to Finglas's helpful answer with respect to mocking, consider a stubbed approach where we override the functionality of callWebsite(). This works quite well in the case where we aren't so interested in the logic of callWebsite as that of the other logic called within pushEvent(). One important thing to check is that callWebsite is calledwith the correct URL. So, first change is to the method signature of callWebsite() to become:
protected String callWebsite(String url){...}
Now we create a stubbed class like this:
class MyClassStub extends MyClass {
private String callWebsiteUrl;
public static final String RESPONSE = "Response from callWebsite()";
protected String callWebsite(String url) {
//don't actually call the website, just hold onto the url it was going to use
callWebsiteUrl = url;
return RESPONSE;
}
public String getCallWebsiteUrl() {
return callWebsiteUrl;
}
}
And finally in our JUnit test:
public class MyClassTest extends TestCase {
private MyClass classUnderTest;
protected void setUp() {
classUnderTest = new MyClassStub();
}
public void testPushEvent() { //could do with a more descriptive name
//create some Event object 'event' here
String response = classUnderTest.pushEvent(event);
//possibly have other assertions here
assertEquals("http://some.url",
(MyClassStub)classUnderTest.getCallWebsiteUrl());
//finally, check that the response from the callWebsite() hasn't been
//modified before being returned back from pushEvent()
assertEquals(MyClassStub.RESPONSE, response);
}
}
Create an abstract class WebsiteCaller which would be a parent of ConcreteWebsiteCaller and WebsiteCallerStub.
This class should have one method callWebsite (String url). Move your callWebsite method from MyClass to ConcreteWebsiteCaller. And MyClass will look like:
class MyClass {
private WebsiteCaller caller;
public MyClass (WebsiteCaller caller) {
this.caller = caller;
}
public String pushEvent (Event event) {
//do something here
String url = constructURL (event); //construct the website url
String response = caller.callWebsite (url);
return response;
}
}
and implement method callWebsite in your WebsiteCallerStub in some way appropriate for testing.
Then in your unit test do something like this:
#Test
public void testPushEvent() {
MyClass mc = new MyClass (new WebsiteCallerStub());
mc.pushEvent (new Event(...));
}