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

陌路散爱 提交于 2020-06-09 10:59:46

问题


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?


回答1:


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




回答2:


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.




回答3:


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);



回答4:


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.




回答5:


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)




回答6:


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.



来源:https://stackoverflow.com/questions/11785708/how-do-i-unit-test-a-grails-service-that-uses-a-converter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!