In my Grails 2.2 application I make some calculations which requires Locale to be set correctly. Therefore I provide this configuration block in my application, as mentioned elsewhere.
grails-app/config/spring/resources.groovy:
beans = {
localeResolver(org.springframework.web.servlet.i18n.SessionLocaleResolver) {
defaultLocale = new Locale("da","DK")
java.util.Locale.setDefault(defaultLocale)
}
}
Now, as also suggested by other questions and answers, this works in my context for the running application but not for unit tests.
I made this snippet to verify (on a page in the application):
<h2>Locale settings</h2>
<p>The following properties relevant to Locale is configured:</p>
<pre>
LocaleContextHolder.locale: '${org.springframework.context.i18n.LocaleContextHolder.locale}'
java.util.Locale.getDefault(): '${java.util.Locale.getDefault()}'
RequestContextUtils.getLocale(request): '${org.springframework.web.servlet.support.RequestContextUtils.getLocale(request)}'
session['SessionLocaleResolver.LOCALE']: '${session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE']}'
</pre>
which renders
Locale settings
The following properties relevant to Locale is configured:
LocaleContextHolder.locale: 'da_DK'
java.util.Locale.getDefault(): 'da_DK'
RequestContextUtils.getLocale(request): 'da_DK'
session['SessionLocaleResolver.LOCALE']: ''
But for unit testing it does not work
The problem occurs for my unit test (I need java.util.Calendar weeks to start on Mondays (default for da_DK, but the week starts on Sunday (default for en_* locales).
In this case I made two test cases:
In test/unit/DefaultLocaleSpec.groovy:
import grails.test.mixin.TestMixin
import grails.test.mixin.web.ControllerUnitTestMixin
import org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletRequest
import org.springframework.web.servlet.support.RequestContextUtils
import spock.lang.Specification
#TestMixin(ControllerUnitTestMixin)
class DefaultLocaleSpec extends Specification {
// ---------------------------------
// Locale verification (affects java Calendar calculations)
// ---------------------------------
def "locale (request) should be set to Danish, so that week starts Monday"() {
given:
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
when:
Locale result = RequestContextUtils.getLocale(request)
then:
result == new Locale("da", "DK")
}
def "locale (default) should be set to Danish, so that week starts Monday"() {
when:
Locale result = java.util.Locale.getDefault()
then:
result == new Locale("da", "DK")
}
The two tests fail with the following messages:
Condition not satisfied:
result == new Locale("da", "DK")
| | |
en | da_DK
false
at DefaultLocaleSpec.locale (request) should be set to Danish, so that week starts Monday(DefaultLocaleSpec.groovy:27)
Condition not satisfied:
result == new Locale("da", "DK")
| | |
en_US | da_DK
false
<Click to see difference>
at DefaultLocaleSpec.locale (default) should be set to Danish, so that week starts Monday(DefaultLocaleSpec.groovy:35)
One workaround I found was to add the following to the unit test file:
def setupSpec() {
java.util.Locale.setDefault(new Locale("da", "DK"))
}
I feel tempted to pick that as a solution, but then I may have to add it to all my unit test file to fix the locale. And it seems like repeated work. I prefer my code more DRY (don't repeat yourself).
Option to change my machine's default Locale.
This I like to avoid, since everything I have to do to modify my setup, my colleagues also have to learn. Less customization is better. The more I can put inside the application, the better for me, my colleagues and any maintainers of the code :)
Question
This pinpoints my actual problem: I want to set up correct (default) locale also for the unit testing environment. How to do that – in a DRY way?
I prefer to make one change in one file which globally affects my app.
Related questions
These related questions do not quite answer or solve my problem (but have related ideas)
SO: How can I force Grails to use only one language? – suggests all problems are solved by setting locale in resources.groovy but does not address unit testing
SO: Retrieve active locale in Grails application – suggestions to read and change locale and default locale (does not address unit testing)
Related
Usually I was ending up writing test cases for a Domain by writing them for constraints and any custom methods(created by us in application) as we know we shouldn't test obvious.
But the time we started using coverage plugin, we found that our domains line of code is not fully covered which was due to gorm hooks(onInsert, beforeUpdate) that we never wrote test cases for.
Is there a way we can test these. One possible way that seems obvious but not suitable is to call another method(containing all code which was earlier in hooks) within these hooks and test that method only and be carefree for hooks.
Any solutions...
Edit
Sample code in domain that I want to unit-test:
class TestDomain{
String activationDate
def beforeInsert() {
this.activationDate = (this.activationDate) ?: new Date()//first login date would come here though
encodePassword()
}
}
How can I unit-test beforeInsert or I would end up writing integration test case?
Perhaps a unit test like:
import grails.test.mixin.TestFor
#TestFor(TestDomain)
class TestDomainSpec extends Specification {
def "test beforeSave"() {
given:
mockForConstraintsTests(TestDomain)
when:
def testDomain = new TestDomain().save(flush:true)
then:
testDomain.activationDate != null
}
}
What is the best way to unit test an Ember model without the application running in the test framework?
I couldn't find much information about how to do this. I got something like the following to work, which I think covers my needs, but is there a smarter way to do this? I'm stabbing at the dark a bit with this attempt so I'm guessing there is.
`import { test, moduleFor } from 'ember-qunit'`
`import Subject from 'school/models/subject'`
`import Student from 'school/models/student'`
#Use subclass to remove relationships, add default values so set functions work.
SubjectTester = Subject.extend {
students: null
name: ''
}
StudentTester = Student.extend {
subject: null
name: ''
height: 0
}
moduleFor('model:subject')
#Use _create to skip the store, manually set up relationships
test('Computes tallest student description', ->
elise = StudentTester._create()
elise.set('height', 165)
elise.set('name', 'Elise')
jasmine = StudentTester._create()
jasmine.set('height', 170)
jasmine.set('name', 'Jasmine')
subject = SubjectTester._create()
subject.set('name', 'Maths')
subject.set('students', [elise, jasmine])
equal(subject.get('tallestStudentDesc'), 'Jasmine is the tallest student in Maths')
)
I initially tried using reopen instead of subclassing but couldn't clean up the changes properly...
Would it better to set up test containers and stores? Should I just use integration tests? Am I missing something really obvious? Any pointers will be greatly appreciated.
I am in the middle of upgrading an app from Grails 1.3.7 to 2.2
So far, its been relatively painless and straight forward.
Until we started running the unit tests.
Under 1.3.7, all the tests passed.
Under 2.2, about half are now failing. The tests haven't changed, they are still the old style mockDomain...
What is most concerning to me is that basic gorm features are missing on some of the domain classes.
Things like .list and .get
Failure: testList_NoMaxSpecified_10Shown(com.litle.bldvwr.StreamControllerTests)
| groovy.lang.MissingMethodException: No signature of method: >com.litle.bldvwr.Stream.list() is applicable for argument types: () values: []
Possible solutions: list(), list(), list(), list(java.lang.Object), list(java.util.Map), >list(java.lang.Object)
and
Failure: >testAddFailureOutputToHappyPathWithIntegrationFailure(com.litle.bldvwr.LogParserServiceTests)
| groovy.lang.MissingMethodException: No signature of method: >com.litle.bldvwr.Result.get() is applicable for argument types: () values: []
Possible solutions: get(java.io.Serializable), get(java.lang.Object), >get(java.io.Serializable), getId(), grep(), grep(java.lang.Object)
The general pattern of for this type of failure is:
mockDomain(Phase, [new Phase(id:1, name: 'xxx')])
mockDomain(Result, [new Result(id:1, phase: Phase.get(1), failureOutput:"")])
logParserService.addFailureOutputTo(Result.get(1))
And it is that last get that is causing the no signature error.
While we intend to start using the new Unit Test functionality, I was hoping to avoid having to rewrite the 500+ current tests.
Thoughts, ideas?
-Clark
Using the new #Mock() annotation in your test for the domain objects will inject all the expected mock GORM methods, and you can even just save() your domain objects instead of providing the list in mockDomain() call.
#Mock([Result, Nightly])
class MyTests {
void testSomething() {
def night = new Nightly( name:'nightly1')
night.id=1
night.save(validate: false)
assert Nightly.get(1).name == 'nightly1'
assert Result.count() == 0
new Result(status: Constants.SUCCESS, type: Constants.INTEGRATION,
nightly: Nightly.get(1)).save(validate: false)
assert Result.count() == 1
assert Result.findByStatus(Constants.SUCCESS) != null // yay dynamic finders!
}
}
http://grails.org/doc/latest/guide/testing.html#unitTestingDomains
You'll have to update all your tests to the new ways, but it's much nicer that the old 1.3 ways.
So here is what we found.
With 1.3, you could do:
{
mockDomain(Nightly, [new Nightly(id: 7)])
mockDomain(Result, [
new Result(status: Constants.SUCCESS,
type: Constants.INTEGRATION, nightly: Nightly.get(7))
])
service.callSomething(results, Nightly.get(7))
assert result==Nightly.get(7).property
And it would work just fine. You whoul have a Mock domain object with and id of 7, and the get would work just fine.
Since then, something changed, and you can no longer set the id has part of the create.
What you need to do is this:
night = new Nightly( name:'nightly1')
night.id=1
mockDomain(Nightly, [night])
mockDomain(Result, [
new Result(status: Constants.SUCCESS, type: Constants.INTEGRATION, nightly: Nightly.get(1))
])
and that mostly sets up the mocks correctly.
The issue we ran into next was that outside of the mockDomain call, Nightly.get() would not work.
So now we need to save the "mocked" domains in local variables in order to do post action comparison and checks.
Not a completely horrible solution, but less elegant than we were hoping for.
As part of a Grails project, I'm currently extending my test suite to stuff that need a complete environment to run, like for instance custom HQL and criteria queries, session related issues, etc. I'm using integration tests.
We already have a fairly large number of unit tests (> 500), where we used to mock methods that don't have a Grails mocked counterpart by default (like withCriteria, withNewSession, etc.) using helper functions like this one:
static mockCriteria(Class clazz, returnValue)
{
def myCriteria = new Expando()
myCriteria.list = {Closure cls -> returnValue}
myCriteria.get = {Closure cls -> returnValue}
clazz.metaClass.static.createCriteria = { -> myCriteria }
}
Code could then be tested like this:
mockCriteria(MyClass, [result])
assert myClass.createCriteria.list({ ... }) == [result]
Until now I always managed to meet my needs using this approach.
Now I want to add integration tests that actually check how methods that use criterias and HQL queries behave, in order to facilitate refactoring these queries. I'm stuck by the fact that createCriteria is replaced in my tests and don't recover their initial code after the unit tests phase, preventing me from testing them in the integration phase.
How do you address the problem of mocking criteria (or HQL queries, etc.), while allowing to get the original behavior back in integration tests?
EDIT: Unfortunately, upgrading to Grails 2 is not an option.
I rather mock not criterias, but domain methods that use them.
Plus, Grails 2.0 promise to have criteria support in unit tests - not HQL, though.
Try this:
void setUp() {
super.setUp()
registerMetaClass MyClass
}
Under the Hood
def a = [1, 2, 3]
def oldMetaClass = ArrayList.metaClass
ArrayList.metaClass.find = { Closure cls -> 5 }
assert 5 == a.find{ it == 1}
ArrayList.metaClass = oldMetaClass
assert 1 == a.find{ it == 1 }
And for mockCriteria take a look
https://github.com/fabiooshiro/plastic-criteria
(works with 1.3.7)
I am using both Zend framework and Django, and they both have they strengths and weakness, but they are both good framworks in their own way.
I do want to create a highly modular web application, like this example:
modules:
Admin
cms
articles
sections
...
...
...
I also want all modules to be self contained with all confid and template files.
I have been looking into a way to solve this is zend the last days, but adding one omer level to the module setup doesn't feel right. I am sure this could be done, but should I? I have also included Doctrine to my zend application that could give me even more problems in my module setup!
When we are talking about Django this is easy to implement (Easy as in concept, not in implementation time or whatever) and a great way to create web apps. But one of the downsides of Django is the web hosing part. There are some web hosts offering Django support, but not that many..
So then I guess the question is what have the most value; rapid modular development versus hosting options!
Well, comments are welcome!
Thanks
You can implement sub-modules with relatively little effort in ZF. Let's say you have directory structure such as:
application/
modules/
admin/
cms/
controllers/
views/
controllers/
views/
You'd register the modules like this in your bootstrap (sub-modules use _ to separate the sub-module from the main module):
$frontController->setControllerDirectory(array(
'default' => APPLICATION_PATH . '/modules/default/controllers',
'admin' => APPLICATION_PATH . '/modules/admin/controllers',
'admin_cms' => APPLICATION_PATH . '/modules/admin/cms/controllers'
));
The issue with this is that it would actually use an underline in the URL instead of a slash, so eg: "admin_cms/conteroller/action" instead of "admin/cms/controller/action". While this "works", it's not pretty. One way to solve the issue is to provide your own route for the default route. Since the default Zend_Controller_Router_Route_Module does it almost right, you can simply extend from it and add the wanted behavior:
<?php
class App_Router_Route_Module extends Zend_Controller_Router_Route_Module
{
public function __construct()
{
$frontController = Zend_Controller_Front::getInstance();
$dispatcher = $frontController->getDispatcher();
$request = $frontController->getRequest();
parent::__construct(array(), $dispatcher, $request);
}
public function match($path)
{
// Get front controller instance
$frontController = Zend_Controller_Front::getInstance();
// Parse path parts
$parts = explode('/', $path);
// Get all registered modules
$modules = $frontController->getControllerDirectory();
// Check if we're in default module
if (count($parts) == 0 || !isset($modules[$parts[0]]))
array_unshift($parts, $frontController->getDefaultModule());
// Module name
$module = $parts[0];
// While there are more parts to parse
while (isset($parts[1])) {
// Construct new module name
$module .= '_' . $parts[1];
// If module doesn't exist, stop processing
if (!isset($modules[$module]))
break;
// Replace the parts with the new module name
array_splice($parts, 0, 2, $module);
}
// Put path back together
$path = implode('/', $parts);
// Let Zend's module router deal with the rest
return parent::match($path);
}
}
And in your bootstrap:
$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addRoute('default', new App_Router_Route_Module);
What this does is traverse the path as long as it finds a module, and transparently rewrites the path so that the default Zend_Controller_Router_Route_Module can do the real work. For example the following path: "/admin/cms/article/edit" will be transformed into "/admin_cms/article/edit", which allows the standard convention of the ZF's ":module/:controller/:action" do the magic.
This allows you to have nice modular structure with self-contained modules, while still use pretty, logical URLs. One thing you want to make note of is that if you use Zend_Navigation and specify the navigation items using module/controller/action parameters, you need to tell ZF how to correctly build the URL using "/" instead of "_" in module names (by default ZF uses the :module/:controller/:action spec when it builds the URLs). You can do this by implementing your own Zend_Controller_Action_Helper_Url, like this:
<?php
class App_Router_Helper_Url extends Zend_Controller_Action_Helper_Url
{
public function url($urlOptions = array(), $name = null, $reset = false, $encode = false)
{
// Replace the _ with / in the module name
$urlOptions['module'] = str_replace('_', '/', $urlOptions['module']);
// Let the router do rest of the work
return $this->getFrontController()->getRouter()->assemble($urlOptions, $name, $reset, $encode);
}
}
And in your bootstrap:
Zend_Controller_Action_HelperBroker::addHelper(new App_Router_Helper_Url);
Now Zend_Navigation works nicely with your sub-module support as well.
I (despite of being happy ZF user) would go for Django. In ZF the "fully-modular" application is kind of holly grail. It's nearly impossible (or at least without extreme effort) to create selfcontained modules, instalable like "copy this folder into your modules directory" :) Not sure about Django, but from what I head it's simplier there...