Reputation: 779
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
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
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
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