integration test « Intelligrape Groovy & Grails Blogs

Posts Tagged ‘ integration test ’

Grails : Save time while writing Integration tests

Posted by on May 6th, 2010

Hi Friends,

I always used to spend lot of time writing integration tests as running even a single test involves loading the complete application, which includes loading complete database every time. Then I realized that data which I use for testing is always the same, why can’t we restore the database once created, before we run the test so that at least time spent on loading data can be saved. Following is the script which I wrote and worked for me.

mysqldump --user=myusername --password=mypassword databaseName  /home/amit/proj_dev_backup.sql
mysql -u myusername --password=mypassword < /home/amit/updateTestDatabase.sql
 
cd /home/amit/applicationPath
mv ./grails-app/conf/BootStrap.groovy /home/amit/BootStrap_org.groovy
cp /home/amit/BootStrap.groovy ./grails-app/conf/
 
grails test-app -integration $@
 
mv /home/amit/BootStrap_org.groovy ./grails-app/conf/BootStrap.groovy
rm  /home/amit/proj_dev_backup.sql

In the above script, databaseName is to be replaced with my development environment database, which is expected to be updated. Here BootStrap.groovy file gets replaced temporarily. If we like, we can also load data in a bootstrap.groovy only for development environment, then we won’t need to replace it even temporarily as in the above script.

Following is the updateTestDatabase.sql file used in the above script which creates and updates the test database.

 DROP DATABASE testDatabaseName; CREATE DATABASE testDatabaseName;
 USE testDatabaseName;
 source /home/amit/proj_dev_backup.sql
 exit

We also need to update DataSource.groovy file for the test environment as follows:

test {
	dataSource {
             dbCreate = "update" 
             url = "jdbc:mysql://localhost/testDatabaseName"
	     driverClassName = "com.mysql.jdbc.Driver"
	     username = "myusername"
	     password = "mypassword"
       }
}

Now I just run this script, provides the list of files to be tested (if any) as command line arguments, and see the integration test results much faster then ever before.

Hope this helped!

~~Amit Jain~~
amit@intelligrape.com

http://www.IntelliGrape.com/

Posted in Grails

Grails Integration Tests : Access your application path

Posted by on January 21st, 2010

Hi Friends,

Recently I needed to access my grails application’s path while writing an integration test. I tried to do it with servlet context, Application Holder and few more options. But none worked. Then I encountered the simplest way as given below, which worked.

System.properties['base.dir']

Cheers!
~~Amit Jain~~
amit@intelligrape.com
IntelliGrape Softwares

http://www.intelligrape.com/

Posted in Grails

Login user for Integration test when using Jsecurity plugin

Posted by on December 7th, 2009

Hello Friends,

I was using Jsecurity plugin in my project. There was an action in a controller which needed logged in user information and I was finding it difficult to write an integration test for the same. Then Brent Fisher shared the following code which worked nicely for both services and controllers:

import org.jsecurity.SecurityUtils
import com.aps.domain.security.JsecUser
import org.jsecurity.subject.Subject

class MyControllerTests extends GrailsUnitTestCase {	

  protected void setUp() {
	super.setUp()	
	//following code sets admin as a logged in user				
	def subject = [isAuthenticated: true,
		       principal: "admin"
		      ] as Subject

	SecurityUtils.metaClass.static.getSubject = {-> return subject }
	Subject.metaClass.getPrincipal = {-> return "admin" }
	...
  }	
 ...
}	

Using metaclass, We changed the implementation of getPrincipal() and getSubject() to work in our way. So looking at this, I could see the power of a metaclass, which can be used to change or add new method implementations to an API which is not even accessible to us.

Cheers!

~~Amit Jain~~
amit@intelligrape.com
IntelliGrape Softwares

http://www.intellgrape.com

Posted in Grails

Grails: Few tips for writing integration tests

Posted by on November 5th, 2009

Just thought I would share with you few tips or key points we should remember while writing integration test cases:

1.  Flush and clear the session object for every single test case for example

class FooTests extends GroovyTestCase {
  def sessionFactory
  void setUp() {
    sessionFactory.currentSession.flush()
    sessionFactory.currentSession.clear()
  }
}

2.  Drop and create the test database before you run integration test: Recently I found, after commiting my integration tests in the repository, some started failing and to my surprise, at the same time that failing test passed on my machine. Later I discovered it was because of some database issue. Since then I have made it a practice to drop and recreate the database again before commiting it to the repository, and then run the test cases to ensure that all test passes.

drop database <myTestDatabase>;
create database <myTestDatabase>;

Note :If you use in-memory database you may not need to follow this step.

3.  Make different test cases to test different methods or even parts of it defined in a controller or a service: for example

 void testAccountService_addSavingsAccount() {...}
 void testAccountService_addCheckingAccount() {...}
 void testAccountService_addSavingsAccount_invalidName() {...}  //to test the expected exceptions

This would make your test cases more understandable and focussed on individual task.

4.  Avoid making your test case depedent upon the data. Otherwise there is high probability that it would break if any changes were made to the data

Lets have a look at the sample code for Integration test written for the controller:

class AccountControllerTests extends GrailsUnitTestCase {
    def accountService
    def sessionFactory
    def renderMap
    def controller

    protected void setUp() {
        super.setUp()
        controller = new AccountController()
        controller.accountService = accountService
        sessionFactory.currentSession.flush()
        sessionFactory.currentSession.clear()
        AccountController.metaClass.render = {Map map ->	//This is to access model when view or template is rendered in the controller
            renderMap = map
        }
    }
   public void testSave() {
        def oldCount = Account.list().size()
        loadParams()
        controller.save()
        assertEquals "Created a new account", renderMap.model.status //accessing model values rendered with view/template
        assertEquals(oldCount + 1, Account.list().size())   //not being dependent on the data
    }

   private void loadParams() {
        def params = [routeTransit: '789456124', accountNumber: '23444', accountType: "ACH",...]
        controller.params.putAll(params)
    }
}

Hope this helped!

Cheers!
~~Amit Jain~~
amit@intelligrape.com
IntelliGrape Softwares

http://www.intelligrape.com

Posted in Grails