John Little
John Little

Reputation: 12343

grails 2.4.4 integration test not using the test datasource

Help!

Our plugin project integration tests should hit the database specified in the datasource.groovy, but for some reason they ignore it, and do it in memory.

Its a plugin which provides the core services (i.e. DB access) to several grails apps which are each a grails application.

Datasource.groovy looks like this:

dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
}
environments {
    development {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:mysql://127.0.0.1:3306/db"
            username = "someuser"
            password = "somepass"
        }
    }
    test {
        dataSource {
            dbCreate = "update"
            url = "jdbc:mysql://127.0.0.1:3306/db"
            username = "someuser"
            password = "somepass"
        }
    }
    production {
        dataSource {
        }
    }
}

The test (SiteIntegrationSpec.goovy)

import grails.test.mixin.TestFor
import grails.test.spock.IntegrationSpec

@TestFor(Site)
class SiteIntegrationSpec extends IntegrationSpec {
    static transactional = false

    def setup() {
    }

    def cleanup() {
    }

    void "test something"() {
        when:
        Site site
        site = new Site(name: "asdf", description: "asdfsd").save(failOnError: true)

        then:
        site.id == 3

        when:
        Site site2 = Site.get(1L)

        then:
        site2.name == "root"
    }
}

Data already existing in the site table: ID name description 1 root root 2 test test

The first test should insert a record which will happen to have an ID of 3. It actually inserts with an ID of 1, i.e. its not seeing or hitting the test database, its using some mock or internal db which is not defined anywhere.

The second test fails as instead of retrieving "root" it retrieves "asdf"

What I have tried:

  1. creating a separate DB for test. Didn't help.
  2. specifying -Dgrails.env=test when running tests. Didn't help
  3. running the tests with the DB down. This correctly fails with cant create pool type exception.
  4. changing the test datasource password to an incorrect one - this correctly throws an exception.
  5. grails -Dgrails.env=test test-app com.me.myproject.SiteIntegrationSpec --stacktrace --verbose

So grails is connecting to the test datasource, but then the integration tests are not using it!

Any ideas?

Edit: Site is a domain object:

class Site {
    String name
    String description
}

Upvotes: 3

Views: 2506

Answers (1)

Burt Beckwith
Burt Beckwith

Reputation: 75671

Plugin DataSource.groovy files aren't included in the plugin zip, and if you somehow manually or programmatically include them, they'll be ignored. The same goes for Config.groovy, UrlMappings.groovy, and BootStrap.groovy. In general when something is usable from a plugin, if the application has a file with the same name and location, it overrides the plugin's file, so that would keep this from working also.

You could define a dataSource bean in your plugin's doWithSpring that replaces the one Grails creates based on DataSource.groovy that uses values from a file that exists in the plugin zip, or that is located in the application if that makes sense. Note that there are really 3 DataSource beans and two of them are proxies of the "real" one, so you need to define yours as dataSourceUnproxied so the other two proxy yours and retain the behavior that they add.

Another thing that you will need to fix once you resolve this is your use of unit test annotations in an integration test. Never use Mock, TestFor, or any unit test mixin annotation or base class, since their purpose is to establish a fairly realistic environment that makes up for Spring, Hibernate, installed plugins, and lots of Grails functionality not being available, but in an integration test they are available, and the unit test stuff will stomp on the real instances.

Also - why are you using static transactional = false? This disables an important integration test feature where all of your test methods run in a transaction that is rolled back at the end of the tests pass or fail. This ensures that nothing you do in a test influences other tests - everything is independent. If you disable this, you need to undo all of the changes, and it's easy to miss some and introduce false negatives or worse - false positives - into your tests.

Upvotes: 2

Related Questions