What is the correct way to mock a declarative REST client when unit testing a Grails service?
Details
I am using Micronaut's declarative HTTP client in my Grails 4 app.
I tried to unit test the client using Ersatz, but I couldn't get it working after several days:
How do I configure Micronaut #Client in a grails test environment?
Now, I'm trying to unit test a service that uses it, using the standard approach for mocking dependencies:
class MyServiceSpec extends Specification implements
ServiceUnitTest<MyService> {
MyRestClient myRestClient = Mock()
def setup() {
service.myRestClient = myRestClient
}
...
}
This gives me a NoSuchBeanDefinitionException.
I have found through trial and error that declarative client does not work with def myRestClient, like other Grails beans. It must be #Autowired.
at org.grails.testing.GrailsUnitTest$Trait$Helper.defineBeans(GrailsUnitTest.groovy:99)
at grails.testing.services.ServiceUnitTest$Trait$Helper.mockArtefact(ServiceUnitTest.groovy:58)
at org.grails.testing.ParameterizedGrailsUnitTest$Trait$Helper.getArtefactInstance(ParameterizedGrailsUnitTest.groovy:48)
at grails.testing.services.ServiceUnitTest$Trait$Helper.getService(ServiceUnitTest.groovy:85)
at com.mycompany.MyServiceSpec.setup(MyServiceSpec.groovy:##)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.MyRestClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1662)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1221)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1175)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:595)
... 15 more
This turned out to be a bug in Grails 4.0.1. The issue seems to be fixed in 4.0.2.
https://github.com/rmorrise/client-spec/tree/mock-client
Props to #erichelgeson and the folks from the Grails slack channel for their help!
Related
I wrote an simple HTTP utility class, which takes a HTTP method name and a requesting URL then return the response.
In my Grails app, several Services will use this utility to get results of some Web API calls. However, I don't know how to unit test these Services. The utility is so simple that it only uses HttpURLConnection to execute HTTP requests, no any other dependencies.
How should I unit test these Services? Should I make the utility as a property of the Services, so that this utility can be injected and mocked on them?
Any suggestions?
You can create a MockHttpUtility, and then use it for test environment.
You can modify resources.groovy so that for tests, the mockService will be injected in your services/controllers instead of real service.
switch(GrailsUtil.environment) {
case "test":
httpUtil(MockHttpUtil) {bean ->
bean.autowire = "byName"
}
}
This would work for integration tests.
For unit tests, you can define the mock service as below
void testFoo() {
defineBeans {
httpUtil(MockHttpUtil)
}
}
You can design mock http util such that it returns the expected response when called. Eg, you can have a constructor or a setter that will take the expected response, and when the utility method is called with http method and url, it will return the given response.
I have a service that has a method that makes a rest call using apache httpclient. I want to test the call using junit but i do not want to mock out the call but mock out the server that it is making the call to
My question is, is it possible to mock out a server using something like mockwebserver so that if you make a request to a specific url that this will be picked up from the service (without mocking the service) rather then going off to the real server?
HttpClient is an interface so you can return a mock in your tests.
Try Jadler (http://jadler.net), an open source library for creating stub/mock http servers. It should provide you everything you need (I'm one of its developers).
My application should show a list of stuff over RESTful WebServices.
This list of stuff is generated via an EJB which is deployed in JBoss AS 6 in a .jar.
My question is, how do I get this list of stuff in order to show it via Web Services?
If I try to inject #EJB in the stateless bean annotated with #WebService, and try to invoke the method that generates the list, I get an error saying that #EJB cannot be resolved (or imported). (fixed it, needed to modify maven dependencies).
Now I get a NullPointerException when I call the supposedly injected EJB...
I am using the webapp archetype from Maven, which contains an EAR, a JAR and a WAR.
I am at a total loss here, been trying to figure this for almost a week.
Thanks in advance!
--EDIT-- code and typo fixed
This is my stateless bean which SHOULD be exposed as a WebService (according to:
http://www.adam-bien.com/roller/abien/entry/restful_calculator_with_javascript_and )
#Stateless
#Path("/MyRESTApplication")
public class HelloWorldResource {
#EJB
private TestBean testBean;
#GET()
#Produces("text/plain")
public String sayHello(String name) {
return testBean.doMoreStuff();
}
}
the doMoreStuff() function simply returns "HELLO!".
I want to export a Web-Service which was implemented as a stateless EJB. I know that these WebServices were hanled by the EJB Container, when they are annotated as #Stateless + #Webservice. Is it possible to route all incoming requests to this Webservice through a Servlet-Filter.
The Servlet-Filter works when my Java-Class is annotated #Stateful and #Webservice, or just #Webservice. But not in conjunction with #Stateless. Anyway to register a Servlet Filter for an EJB Webservice?
Many thanks!
Adem
UPDATE:
Solved this problem, by annotating WebService Class with
#WebService
#RequestScoped
Filter works only in this constellation and acting as Stateless class for WebService consumer.
Lifecycle Callbacks : You can have a method with #PostConstruct annotation which gets called after the container has initialized the bean.
Interceptor : You can have a interceptor class which gets invoked when applied at bean class/method level by annotation #Interceptors(ProcessMonitor.class).
Note : I haven't tried it in conjunction with #Webservice.
I have a layered application that looks like this:
#PreAuthorize('isAuthenticated()')
#Controller
public class MyController {
#Autowired
MyService service;
}
#Service
public class MyService {
#Autowired
MyDao dao;
}
public interface MyDao {
}
#Repository
public class MyDaoImpl implements MyDao {
}
I want to test the AOP-dependent #PreAuthorize annotation, so I use the SpringJUnit4ClassRunner which creates a test AuthenticationManager and MyController.
If the #ContextConfiguration does not include any bean matching MyService, test initialization fails because it can't resolve the bean.
If I didn't need AOP, I would use Mockito test runner and inject Mockito.mock(MyService.class). But if I try and do it with spring runner, again my test fails because it can't resolve MyDao for the service (even though the service a mock).
I definitely don't want to mock the whole object graph. I'd rather it stopped on the mocked service. How can I do it?
Your MyService should implement an interface, and you should mock the interface instead of the class. Then you won't need a DAO implementation. You might also, perhaps, be running into a similar issue that I faced while trying to test a JAX-RS resource class in Jersey. The problem is how to deploy a single bean into a Spring container but mock its dependencies. I wrote a blog post on it that might help you out if this is the problem you're facing. In particular, the final solution may be of help.