emiles
emiles

Reputation: 779

Grails Unit Testing

This isn't a question but maybe a request for comments about general unit testing in grails.

I've been banging my head against writing unit tests and except for very, very simple use cases, I most always run into some snag. What I'm finding is anytime something needs to be mocked, like grailsApplication, or some other framework object, unit testing starts falling apart or you need to jump through so many hoops that it becomes counter-productive. Then, on top of this, the migration from 1.X to 2.X caused all sorts of unit/integration test refactoring, which in the long run made things easier, but still caused failures during migration.

My answer ... move all semi-complicated testing into integration tests and don't look back. It works when everything is spun up. It takes longer to run, but not longer than dealing with the unit testing headaches.

The latest, not the first, use case that caused my heartburn was trying to unit test a service that creates a domain object, which has a dependency on grailsApplication.config, and does something with said domain object. I tried most everything I found to fix it (except what actually works!), nothing worked, I move the unit test code to an integration test, and it passed on first run. Unit test complained that 'config' could not be called on a null object or something like that, meaning grailsApplication was not there.

I really don't see the need to write unit tests when integration tests work for everything, all the time.

Using grails 2.2.0.

Upvotes: 2

Views: 3885

Answers (3)

sf_jeff
sf_jeff

Reputation: 384

I both agree and disagree with the original asker's post. My response is, there are some things that unit tests are better for, but his current sticking point might not be one of them.

In my opinion, the best code has regions of complex behavior with extremely well defined input and output and regions of simple behavior with loosely defined input and output but will have no regions of loosely defined complex behavior. Obviously configuration and light business logic goes in the latter category and any "engine" code goes in the former category.

The original post references uses of configuration, which is by definition loosely defined, so it would be best if logic that is found near there is kept relatively simple. Any complex behavior near that can be abstracted out into general, parameterized behavior and this behavior can be unit tested. But for the functionality involving configuration, an integration test would probably be better.

Upvotes: 1

Meam
Meam

Reputation: 266

I also ignore unit test for most part. It causes problem for me more than it worth. However, I wrote integration tests for almost all part. (though not all combinations, that's impossible.)

My main purpose of test is to prevent regression, mostly from code change in related part. Integration test suits me perfectly.

Upvotes: 0

dmahapatro
dmahapatro

Reputation: 50275

Would not agree to that.

Unit tests are the building blocks of a perfectly written app following the concept of TDD. The rationale of having a unit test is to isolate a module from injections and try to test a it with all the dependencies provided by the test environment instead of the dependencies provided by the container.

I can understand the pain point here. You have to go through some boiler plate setup but that is the main point in having unit tests.

Integration tests provides everything on your plate (dependency injection on top) but this does not solve the purpose of testing a module in isolated conditions. I have been in the same path as yours upgrading bunch of projects from Grails 1.3.4 to Grails 2.2.0 and faced the same problem. But I took some time to understand the highly flexible mocking mechanisms provided by latest version of Grails. For example;

@Mock : You do not need to use mockDomain any more, the annotation will take care of mocking domain classes in Unit test cases. Not to forget build-test-data plugin makes it more convenient to mock

@TestFor: You can use @TestFor annotation for grails artefacts (controller, services) which will do some injections for you and you would end up following few conventions.

Not to forget the power of mixins.

You can find more about them here.

Now to answer your problem you faced while unit testing the service class. grailsApplication is readily available in unit test cases, you do no need to mock or try to get it from application context. Just use grailsApplication in the test class like:

//Unit test
void testSomething(){
   assert "Hello" == grailsApplication.config.foo.bar.hello
}

//Config.groovy
foo.bar.hello=hello

Isn't that simple? Remember not to def grailsApplication in Unit Test class.

On the other hand, integration tests are a better approach if you are testing a service in particular, or a portion of service which uses more than on module.

We make tests to fail in order to pass. Writing a passing test case makes me uncomfortable and think that I am doing something wrong. :)

Upvotes: 5

Related Questions