It is usually more complicated to write unit tests due to having to deal with mock objects than integration tests in a large Grails project. This article even suggests we can ev
I've worked on 3 large grails apps, and innumerable smaller ones. My current project has a mix of unit and integration tests (currently 2110 unit tests and 493 integration tests).
I've spent a bunch of time trying to improve testing speed as well as making tests more maintainable.
My integration tests are often a hybrid where if I'm testing a service, I might mock out some other services/methods being called to ensure I get the values that I want, but leave in other integration pieces to exercise HQL or database integration. To this end, I use prototype instances of what are normally singleton services so that I can muck with the service instance without polluting later tests.
I find the build-test-data plugin invaluable for creating maintainable unit tests as it lets me create test data where I explicitly populate the pieces I need and let the plugin fill in the other required details. Creating test data in integration tests is easier for me than mocking it out in unit tests.
If you do use both integration and unit tests, eventually the speed of running all of the tests serially will become an impediment. My team uses the splitTests.groovy script to spin off two separate threads, one for unit tests, one for integration tests. This exercises our tests about 40% faster. Further parallelization is possible, but we haven't gone there yet (and the current grails gant scripts are pretty nasty under the covers, I'm looking forward to the gradle rewrite in grails 2.0).
Unit tests are nice for hitting all of the conditional nooks and crannies of a method (though if you've got too many, your cyclomatic complexity is probably too high and you should refactor). Integration tests are useful for exercising database and service integration as well as helping you understand what you've broken when you change a piece of code.
I think that the refactoring courage that you get from having high test coverage is partly dependent on some of the tests being integration tests. If all you have are unit tests that don't interact with other code pieces, you won't be alerted of affected areas when you make a code change, and because groovy is a dynamic language, the compiler likely won't help you find these areas either.
I always write my tests as unit tests if possible. I do this because:
An example of where I would write an integration test is if I want to test a Spring bean that I've defined in resources.groovy
. Although I could instantiate the class and test it directly, my test would then need to know the current implementation class of that bean (which might change).
In the long-run I think it's actually more complicated to write integration tests, because the cost of maintaining them over time is higher than unit tests. Groovy/Grails has excellent support for mocking/stubbing, so the cost of mocking dependencies in unit tests is relatively low. Here's a real-world example from one of my unit tests where I:
messageSource
Spring bean that would normally only be available in an integration testvalidate()
method, inspect the .errors
property, etc.class MyUnitTests extends GrailsUnitTestCase {
MessageSource messageSource
protected void setUp() {
super.setUp()
// mockForConstraintsTests is a method provided by GrailsUnitTestCase
[Complex, CategoryCommand].each {mockForConstraintsTests(it)}
// 'mockMessage' will be returned by every method call on messageSource
messageSource = {Object[] args -> "mockMessage"} as MessageSource
}
}