Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.0-RC3
-
Fix Version/s: 1.1-RC1
-
Component/s: Configuration
-
Labels:None
-
Environment:ubuntu 7.10, sun-jdk6, grails 1.0-rc3
-
Testcase included:yes
Description
I add codes below in init closure of grails-app/conf/BootStrap.groovy
String.metaClass.newReader = {->
new StringReader(delegate)
}
And codes below in one Test file:
void testSomething() {
String fileContents = "data.log"
Reader reader = fileContents.newReader()
}
When I run "grails test-app", it is failed because no newReader method for String class.
But If I run grails shell, and input "aaa".newReader(), it works fine.
So I think the bootstrap class doesn't be called at test-app command.
Attachments
-
$i18n.getText("admin.common.words.hide")
- expotest-bug-report-20122007.zip
- 19/Dec/07 11:33 PM
- 69 kB
- Simon Lei
-
- grails-app/conf/BootStrap.groovy 0.2 kB
- grails-app/conf/Config.groovy 4 kB
- grails-app/conf/DataSource.groovy 0.6 kB
- grails-app/conf/UrlMappings.groovy 0.2 kB
- grails-app/conf/spring/resources.xml 0.3 kB
- grails-app/domain/Book.groovy 0.0 kB
- grails-app/i18n/messages.properties 2 kB
- grails-app/i18n/messages_de.properties 3 kB
- grails-app/i18n/messages_es.properties 3 kB
- grails-app/i18n/messages_fr.properties 2 kB
- grails-app/i18n/messages_it.properties 2 kB
- grails-app/i18n/messages_ja.properties 2 kB
- grails-app/i18n/messages_nl.properties 3 kB
- grails-app/i18n/messages_ru.properties 4 kB
- grails-app/i18n/messages_th.properties 5 kB
- grails-app/.../messages_zh_CN.properties 2 kB
- grails-app/views/error.gsp 1 kB
- grails-app/views/layouts/main.gsp 0.7 kB
- test/classes/Book.class 5 kB
- test/classes/BookTests.class 9 kB
- test/classes/BootStrap$_closure1.class 2 kB
- test/.../BootStrap$_closure1_closure3.class 2 kB
- test/classes/BootStrap$_closure2.class 2 kB
- test/classes/BootStrap.class 5 kB
- test/classes/Config$_run_closure1.class 3 kB
- test/.../Config$_run_closure1_closure2.class 2 kB
- test/.../Config$_run_closure1_closure2_closure3.class 3 kB
- test/.../Config$_run_closure1_closure3.class 2 kB
- test/.../Config$_run_closure1_closure3_closure4.class 3 kB
- test/classes/Config$_run_closure2.class 2 kB
$i18n.getText("admin.common.words.show")- expotest-bug-report-20122007.zip
- 19/Dec/07 11:33 PM
- 69 kB
- Simon Lei
-
- TestApp.patch
- 08/Apr/08 3:42 PM
- 1 kB
- Corey
Activity
- All
- Comments
- Work Log
- History
- Activity
- Git Commits
I'm not sure it is wise to call bootstrap during test-app for integration tests. Bootstrap is typically used to setup production data, why would this be relevant in a test?
I'll explain the situation as I perceived it, and the circumstances which brought me to the desire to use BootStrap (or a BootStrap... TestBootStrap.groovy?).
For one, I see that test is an environment, just like development and prod, and you can test for environment in BootStrap and execute code as appropriate to the environment - so, I wasn't thinking of BootStrap as "production data only", but rather "data initialization for all environments and/or specific environments".
Then secondly, I have alot of fixture data that my app requires for integration testing - initializing all that data in base fixture classes has become ridiculously tedious - made worse because all the initialization necessary for my integration tests exactly mirrors the same data that I use in BootStrap for a prestine product app - made doubly worse because all that data gets re-initialized on every single test.
An example of the sort of initialization I need for integration tests and for a prestine instance of the app:
// UserStatus
new UserStatus( name: 'void' )
.addToStates( new UserState( name: 'pending' ) )
.addToStates( new UserState( name: 'exception' ) )
.addToStates( new UserState( name: 'voided' ) )
.save(flush:true)
new UserStatus( name: 'active' )
.addToStates( new UserState( name: 'enabled' ) )
.addToStates( new UserState( name: 'disabled' ) )
.save(flush:true)
... now, I have about 10 of those (ServiceOrderState, AccountStatus, etc. etc) - with many of them having far more States and Status'; and that's not including similar setups for Groups and Roles and a default superuser, and the required SiteConfiguration; and other stuff like: Site.metaClass.'static'.getSiteName = { -> Site.findAll()[0]?.siteName } .
So not only do I have to repeat all that in base fixtures for my tests, but it all gets-re-initialized for every test.
Without being able to run a BootStrap for integration tests, I would need to:
0 - put data-initialization into BootStrap
1 - 'grails development run-app'
2 - manually import MyApp_dev db to MyApp_test
3 - 'grails test-app MyIntegrationTest'
4 - repeat everytime I need to change the fixture data
... it was when I found myself about to begin the above process, that I realized: "I should really be able to use BootStrap..., this is redundant and frustrating"
And to show just how gnarly my integration fixtures have gotten, along with all that base-level fixture data I need, there's the issue where many of my integration tests are rather complex in their associations:
To test a Transaction, I need all TransactionStates and TransactionStatus, and a Transaction also needs a ServiceOrder, ServiceOrder needs This and That and FooBar, FooBar needs Blah and Goober... etc. etc. – so part of my test environment BootStrap would be to create and store default/test entities so that doing an integration tests such as 'TransactionTests.testExecuteTransaction'() doesn't require a boat load of complex setUp's and multiple base fixtures.
So the issues - as I see them - that I'm running into without integration tests being able to run BootStrap, are: dry violation, innefficiency, inconviencience
If it's actually my practices that are the actual underlying problem, I would appreciate any advice on the matter - thanks!
I have the same situation as Corey above.
I need to run Bootstrap on any database that does not have a specific set of domain objects populated in it for a minimal 'runnable' configuration. This minimal initial setup is needed for any test code to run or any browser end user to operate on the application in production.
I have the code smart enough to detect when the users have modified the configuration from the default and thus not perform any inserts to prevent deleted object from re-appearing.
The bootstrap process should only run once per database startup in test mode so adding it to the setUp() method of each test is not desirable.
The needed domain objects will be inserted every time in test mode(memory database) and only once in production(real DB).
I added the following code the TestApp.groovy(grails 1.0.1) around line 328
populateTestSuite(suite, testFiles, classLoader, appCtx, "test/integration/")
if (suite.testCount() > 0) {
+ // 1-time initialization for integration tests via BootStrap
+ GrailsConfigUtils.executeGrailsBootstraps(app, appCtx, servletContext )
int testCases = suite.countTestCases()
NOTE: Also added import for GrailsConfigUtils
Graeme,
What if the grails-app/conf/Bootstrap.groovy was changed to one of the following :
class BootStrap {
def init = { servletContext -> }
def initProduction = { servletContext -> init(servletContext) }
def initTest = { servletContext -> }
def initDevelopement { servletContext -> }
def destroy = {
}
}
or
import grails.util.GrailsUtil
class BootStrap {
def init = { servletContext -> }
def destroy = {
}
def initialize = { servletContext ->
switch(GrailsUtil.environment) { case "development": break case "test": break case "production": init( servletContext) break }
}
}
Then the executeGrailsBootstap code would call the initialize closure instead of the init closure to do the configuration.
Also when grails upgrade is run, these methods could be added without affecting the current function and behavior of the various run modes.
This way the existing apps can continue as they are behaving now and new apps will get the new boilerplate. Both can be configured as needed specific to the application after the upgrade.
I've come across this issue recently as we are using Bootstrap to create some basic test data and run an automatic Liquibase migration.
Corey's patch seems to work well, and if it did cause people issues that can wrap prod-only init code in an if(GrailsUtil.environment == .. type line.
Until Grails gets an equivalent of Rails' Fixture functionality I think we need to allow for Bootstrap to be used to create test data for integration tests
This is completely counter-intuitive IMO.
BootStrap should run for integration tests.
i just ran into this trying to use test data created by bootstrap when testing. seems like one would want some kind of super one-time SuiteFixture Setup: http://xunitpatterns.com/SuiteFixture%20Setup.html and the corresponding teardown. this would decouple the testing setup and teardown from boostrap.
thanks
Current consensus is to leave this for 1.1 because it will be a breaking change.
There are enough votes on this issue and people suffering from it to justify the change. I will add it to the breaking change list, in the meantime users will have to change their bootstraps too:
import grails.util.* if(Environment.current = Environment.PRODUCTION) { // }
import grails.util.* if(Environment.current = Environment.PRODUCTION) { // }
This came up today on grails-user: http://www.nabble.com/test-app-BootStrap--to16570647.html
A potential solution was provided, the resulting patch attached.
I don't know whether it should occur only when integrationOnly is true, or what other issues may need thinking through; and the patch has hardly been tested.