How do I unit test a Grails service that uses a converter? - json

I have a Grails service that sends out e-mails using a 3rd-party service by doing a HTTP call:
class EmailService {
def sendEmail(values) {
def valueJson = values as JSON
... // does HTTP call to 3rd party service
}
}
I've written a unit test to test this service (because an integration test spins up Hibernate and the entire domain framework, which I don't need):
#TestFor(EmailService)
class EmailServiceTests {
void testEmailServiceWorks() {
def values = [test: 'test', test2: 'test2']
service.sendEmail(values)
}
}
However, when I execute this unit test, it fails with this exception when it tries to do the as JSON conversion:
org.apache.commons.lang.UnhandledException: org.codehaus.groovy.grails.web.converters.exceptions.ConverterException: Unconvertable Object of class: java.util.LinkedHashMap
I then re-wrote my unit test to just do the following:
void testEmailServiceWorks() {
def value = [test: 'test', test2: 'test2']
def valueJson = value as JSON
}
And I get the same exception when it tries to do the as JSON conversion.
Does anyone know why I'm getting this exception, and how I can fix it?

Even though you are testing a service, you can apply the #TestMixin(ControllerUnitTestMixin) annotation to your test class to get Grails to set up the JSON converter.

The as JSON magic is created when the domain framework spins up.
You have to either change your test to an integration one or mock the asType.
def setUp(){
java.util.LinkedHashMap.metaClass.asType = { Class c ->
new grails.converters."$c"(delegate)
}
}
Rember to clean up after yourself in the tearDown, you wouldn't want metaprogramming leaks in your test suite.
def tearDown(){
java.util.LinkedHashMap.metaClass.asType = null
}
Edit:
If you come from the future, consider this answer: https://stackoverflow.com/a/15485593/194932

As Grails 3.3.x grails-test-mixins plugin is deprecated. #see migration guide.
For this problem you should implement GrailsWebUnitTest which is coming from Grails Testing Support Framework.

you can initialise the JSON in the setUp() . There are various marshallers which implement ObjectMarshaller , which need to be added to the ConverterConfiguration for JSON conversion to work.
http://grails.github.io/grails-doc/2.4.4/api/index.html?org/codehaus/groovy/grails/web/converters/marshaller/json/package-summary.html
example :
DefaultConverterConfiguration<JSON> defaultConverterConfig = new DefaultConverterConfiguration<JSON>()
defaultConverterConfig.registerObjectMarshaller(new CollectionMarshaller())
defaultConverterConfig.registerObjectMarshaller(new MapMarshaller())
defaultConverterConfig.registerObjectMarshaller(new GenericJavaBeanMarshaller())
ConvertersConfigurationHolder.setTheadLocalConverterConfiguration(JSON.class, defaultConverterConfig);

I just ran into this, and I really didn't want to implement GrailsWebUnitTest as recommended in another answer here. I want to keep my service test as "pure" and lean as possible. I ended up doing this:
void setupSpec() {
defineBeans(new ConvertersGrailsPlugin())
}
void cleanupSpec() {
ConvertersConfigurationHolder.clear()
}
This is how it happens under the hood when you implement GrailsWebUnitTest (via WebSetupSpecInterceptor and WebCleanupSpecInterceptor).
That said, the converters seem to be meant for use in the web tier, primarily for making it easy to transparently return data in different formats from a controller. It's worth considering why the service you're testing needs the converters in the first place.
For example, in my case, someone used the JSON converter to serialize some data to a string so it could be stored in a single field in the database. That doesn't seem like an appropriate user of the converters, so I plan on changing how it's done. Making the converters available in my service test is a temporary solution to allow me to improve our test coverage before I refactor things.

I was getting the same error when trying to unit test a controller that calls "render myMap as JSON". We use Grails 1.3.7 and none of the other solutions worked for me without introducing other problems. Upgrading Grails was not an alternative for us at the moment.
My solution was to use JSONBuilder instead of "as JSON", like this:
render(contentType: "application/json", {myMap})
See http://docs.grails.org/latest/guide/theWebLayer.html#moreOnJSONBuilder
(I realize this is old, but came here in search for a solution and so might others)

Related

How to use Hystrix with Spring WebFlux WebClients?

I'm using Spring WebFlux with functional endpoints to create an API. To provide the results I want, I need to consume an external RESTful API, and to do that in a async way I'm using a WebClient implementation. It works well and goes like this:
public WeatherWebClient() {
this.weatherWebClient = WebClient.create("http://api.openweathermap.org/data/2.5/weather");
}
public Mono<WeatherApiResponse> getWeatherByCityName(String cityName) {
return weatherWebClient
.get()
.uri(uriBuilder -> uriBuilder
.queryParam("q", cityName)
.queryParam("units", "metric")
.queryParam("appid", API_KEY)
.build())
.accept(APPLICATION_JSON)
.retrieve()
.bodyToMono(WeatherApiResponse.class);
}
As this performs network access, it's a good use case for NetFlix OSS Hystrix. I've tried using spring-cloud-starter-netflix-hystrix, adding #HystrixCommand to the method above, but there's no way to make it trip the circuit, even if I set a bad URL (404) or wrong API_KEY (401).
I thought this could be a problem of compatibility with the WebFlux itself, but setting property #HystrixProperty(name="circuitBreaker.forceOpen", value="true") indeed forces the fallback method to run.
Am I missing something? Is this approach incompatible with Spring WebClients?
Thanks!
#HystrixCommand won't really work, because Hystrix doesn't threat Mono/Flux any different from Java primitives.
Hystrix doesn't monitor content of Mono, but only the result of call public Mono<WeatherApiResponse> getWeatherByCityName(String cityName).
This result is always OK, because reactive-call-chain creation will always succeed.
What you need, is to make Hystrix threat Mono/Flux differently.
In Spring Cloud, there is a builder, to wrap Mono/Flux with HystrixCommand.
Mono<WeatherApiResponse> call = this.getWeatherByCityName(String cityName);
Mono<WeatherApiResponse> callWrappedWithHystrix = HystrixCommands
.from(call)
.fallback(Mono.just(WeatherApiResponse.EMPTY))
.commandName("getWeatherByCityName")
.toMono();

Programmatically instantiate a FeignClient for tests

I have a dead simple FeignClient interface that I would like to "unit"/integration test with a fake HTTP server, WireMock for example. The idea is to test the mapping with a sampled HTTP API response, without configuring a whole Spring Boot/Cloud Context.
#FeignClient(name = "foo", url = "${foo.url}")
public interface FooClient {
#RequestMapping(value = "/foo/{foo-id}/bar", method = RequestMethod.GET)
public Bar getBar(#PathVariable("foo-id") String fooId);
}
Is there any way to programmatically instantiate this interface, like a Spring Data Repository through a *RepositoryFactoryBean ?
I see a FeignClientFactoryBean in the source code, but it is package protected, and it relies on an ApplicationContext object to retrieve its dependencies anyway.
Well, you can fake a real rest client using wiremock for testing purposes, but this is more about containing the functional test, that feign clients themself work. This is mostly not what you really want to test, because the actual need is to test your components using your client behave in a specified way.
The best practice for me is not to make live hard with maintaing a fake server, but mock the clients behavior with Mockito. If you use Spring Boot 1.4.0, here is the way to go:
Consider you have some FooBarService, which internally uses your FooClient to peform some FooBarService::someAction(String fooId), which performs some business logic which needs to work with a foo with given id
#RunWith(SpringRunner.class)
#SpringBootTest(classes = App.class)
class FooUnitTest {
#Autowired;
private FooBarService fooBarService;
#MockBean;
private FooClient fooClient;
#Test
public void testService() {
given(fooClient.getBar("1")).willReturn(new Bar(...));
fooBarService.someAction("1");
//assert here, that someAction did what it supposed to do for that bar
}
}
At this point you first should clarify, what you expect the REST client to respond, when asking for "/foo/1/bar", by creating a mock for exactly that case and give the Bar object you expect to receive for that API, and assert that your application is in the desired state.

Mule: JUnit test case to call a service which is in middle of the Mule flow

I'm newbie for JUnit test case. Please help me on this issue. I have 2 mule flows- first flow having MQ as inbound and it has datamapper to transformer the xml. With the first flow input, i'm calling second flow where we are calling the existing service ( SOAP/HTTP) call. Please find my JUnit below. I'm able to get the success response. But my requirement
1. I need to see the transformer response coming out from the Transformer.( Like how we see via logger component in our flow)
2.Need to override the url (HTTP) through JUnit ( in order to test the error scenario)
public class Request_SuccessPath extends FunctionalTestCase {
#Test
public void BulkRequest () throws Exception {
MuleClient client = muleContext.getClient();
System.out.println("test");
String payload = " <root> <messageName>str1234</messageName><messageId>12345</messageId><DS>123</DS><</root>";
MuleMessage reply = client.send ("vm://test",payload ,null);}
#Override
protected String getConfigResources() {
// TODO Auto-generated method stub
return "src/main/app/project.xml";}
i thought the following snippet will override the url.But it is not
DefaultHttpClient client1 = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://localhost:7800/service);
assertNotNull(response);
3. How to take the control of the flow and see any response inbetween the flow.
Instead of WMQ, i have replaced VM as inbound end point for testing purposes.
4. Is there any chance like without replacing VM can we call directly with WMQ through JUnit TestCase. Kindly help me on this.
I'm using 3.4 version, not using maven as of now. Please help me. Thanks in advance.
1) What do you mean by "see". Would it work logging it? inspecting it while debugging?
2) You should parametrize your endpoint with a variable, something like
and configure a property placeholder as explained here: http://www.mulesoft.org/documentation/display/current/Using+Parameters+in+Your+Configuration+Files
Adding http.port, http.host and http.path variables to mule-app.properties
taking into account that you must set system-properties-mode="OVERRIDE" and then start your Mule server using bin/mule -M-Dhttp.host=your-host -M-Dhttp.port=your-port -M-Dhttp.path=your-path
3) Yes, WMQ has a Java API you can use to interact with it: http://publib.boulder.ibm.com/infocenter/wmqv6/v6r0/index.jsp?topic=%2Fcom.ibm.mq.csqzaw.doc%2Fuj41013_.htm , you will probably found hundreds of examples by googling about it.
Regards.

Understanding Json structure generated by an AJAX-enabled WCF Service

Good afternoon
In Visual Studio 2010 I am able to add to my solution a new item called in AJAX-enabled WCF service. That will add a new a .svc file.
Later, I have created a method just for debugging purposes:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataAccessService
{
[WebGet]
[OperationContract]
public MyClass DoWork()
{
var o = new MyClass
{
Id = 1,
FirstName = "Junior",
LastName = "Mayhe"
};
return o;
}
}
When debugging here is the resulting Json string:
{"d":
{"__type":"MyClass:#MyProject",
"Id":1,
"FirstName":"Junior",
"LastName":"Mayhe"
}
}
The question is, what is this "d"?
Is it some result type code for a Json string, and if so, are there other codes?
thanks in advance
It is only "d", and it is intended as protection against some cross-site scripting attacks.
E.g. consider a method that returns an int array of sensitive data (e.g. bank account balances). It can be returned as:
[10000,12300,15000]
Or:
{"d":[10000,12300,15000]}
The problem is that in the first case, there's a (very advanced and obscure but nevertheless real) attack whereby another site can steal this data by including a call to the service in a tag and overriding the JavaScript array constructor. The attack is not possible if the JSON looks like the latter case.
There was some talk within Microsoft to extend the format beyond just "d", but I don't think it ever went anywhere.
Your response is simply getting encapsulated with a parent object called "d". It was introduced in ASP.NET 3.5 web services as a security enhancement to prevent JSON hijacking.
The client proxies generated for your service will strip out the "d" so you will never really even know it was there. But since you're service isn't really going to be consumed for anything other than AJAX requests, you'll have to access your JSON objects through the ".d" property. I would recommend using JSON2 to parse the response, since not all browsers have native JSON support at the time of this writing.
You can read a little more about the security problem here.

Grails with JAX-RS vs UrlMappings for RESTful Services

I started out looking at the JAX-RS plugin for grails and thought that was the way to go mainly because it was based on JSR-311 and I figure following standards is usually the smart thing to do. However, using Grail's UrlMappings it seems I basically achieve the same thing. I figure I'm missing something, however, we aren't doing anything overly complex. We basically just need to expose CRUD via an API. Example of doing the same thing with both versions:
JAX-RS:
#PUT
#Consumes(['application/json'])
#Produces(['application/json'])
Response putUser(User user) {
user.save(flush:true)
ok user
}
Grails:
def update = {
def user = new User(params['user'])
user.save(flush:true)
render user as JSON
}
Obviously, this is an overly-simplified example and like I said, maybe I'm missing something important. Also, the nice thing about the Grails built in mechanism is I can utilize Content Negotiation along with it.
Anyone have any opinions on this?
I had to make the same decision, and I found it just easier to use URL Mappings because the API was not that complex and there were a limited number of API calls that needed to supported.
If came down to what would be easier to maintain based on the LOE and the resources able to support the implementation.
The jax-rs plugin is very useful if you are creating web services straight to your domain models. It gives you a "generate-resource" command that automatically creates CRUD apis for your model.
grails generate-resource mydomain.Model
This part seems to work fine, however, I encountered quite a few bugs/problems with the plugin that I finally had to implement the REST services using URL-mappings.
Although the URL-mapping method seems to be more coding, it works perfectly.
import grails.converters.JSON
class ModelServiceController {
def id = params.id
def myModel = MyModel.findById(id)
render myModel as JSON
}
Here's the link for grails REST
http://grails.org/doc/1.0.x/guide/13.%20Web%20Services.html