Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Monday, March 10, 2008

Mocking out the logger

I have a simple CachingService that is a wrapper for Ehcache.   I wanted to create a unit test out of CachingService, since it doesn't have any dependencies.  However after running the test I was getting an error:  "groovy.lang.MissingPropertyException:  No such property: log for class:  CacheService".

Oops I forgot I have some logging inside my CachingService class.   At runtime Grails auto-magically injects a "log" property into service classes.  If my test was an integration test then there wouldn't be a problem.   So I have two options, either mock out the logger or run my test as an integration tests.   I decided to mock out the logger, which required me to do the following:

1.  Create a MockLogger class (primarily since I will probably have to mock out the logger in other classes in the future)

class MockLogger {
  void info(message) {}
  void warn(message) {}
  void debug(message) {}
  void error(message) {}
}

2.  Inject my MockLogger as a property named "log" via getLog() into my service class via ExpandoMetaClass

void setUp() {
  CachingService.metaClass.getLog = { -> new MockLogger() }
}

3.  Reset the state of CachingService before dynamically adding the property "log"

void tearDown() {
  def remove = GroovySystem.metaClassRegistry.&removeMetaClass
  remove CachingService
}

There may be other ways to mock out the logger, but this approach seemed simple enough.  Do you have an easier approach?  If so please drop a comment.





Sunday, March 9, 2008

Testing Approach

To be honest I'd don't do as much as testing as I should.  I really understand the value of testing my code and love to see the green bar.  However anytime in the past I needed to write a test that required mocking I always cringed.   Although EasyMock and JMock are great tools they can be a pain sometimes for that code with heavy dependencies.

Groovy has some great support for testing, including:
  • GroovyTestCase (which extends on JUnit)
  • Testing for exceptions via "shouldFail()"
  • First-class mocking support built-into the language
In Grails when you create a controller, domain, job, or service it will automatically create a test class for it.  However it creates them all as integration tests which run slower than unit tests because the entire Grails environment needs to get bootstrapped to success run the tests.   I can understand testing the domain classes as integration tests because they need to hit the database.  

Most of the code that I'm going to write should be in the service layer.  So I need the service layer tests to run quickly so I can get a quick feedback.  Lucky Groovy makes it pretty easy for me to mock out the domain layer in my service tests.   Below is an example of a service layer test that mocks out the "Site" domain object:


void testAccessDataObject() {
  def service = new SampleService()
  def siteMock = new groovy.mock.interceptor.StubFor(Site)
  siteMock.demand.get {id ->
    return new Site()
  }

  siteMock.demand.getName {id ->
    return 'my sample site'
  }

  def results
  siteMock.use {
    results = service.accessDataObject()
    assertEquals 'my sample site', results.name
  }
}

Currently I am on the fence on whether controllers should be written as unit or integration tests.  I am leaning towards integration tests because I will be able to write a test that tests the entire mvc stack.   What are your thoughts on testing the controller?

Just a little tip for running test with grails.  Normally you run the "grails test-app" command to run both the unit and integration tests.  If you just want to run the unit tests you can run "grails test-app -unit" and just the integration tests with "grails test-app -integration".

There's a Grails plugin to integrate Canoo Webtest to able to write functional tests (aka user acceptance tests).  You can write your functional tests in Groovy instead of xml if you desire.  I haven't tried it yet, but there's also a plugin for integrating Cobertura test coverage tool.  

Because of Groovy and Grails excellent testing support I would be a fool to write Siteproducer without testing.  I can't guarantee 100% test coverage, but at least 60% would be great.