How do I setup logging in a grails unit-test?
When I try log.info or log.debug, the .txt output files are empty, even after I tried adding a console appender. What's going on here?
This might help, it's taken from the 1.2 release notes
By default, grails does not show the
output from your tests. You can make
it do so by passing -echoOut and/or
-echoErr to test-app:
grails test-app -echoOut -echoErr
If you extend GrailsUnitTestCase, you ought to be able to use mockLogging(), but the appenders you set up in Grails config won't be applied in a unit test, which works in isolation from the real framework. They'd only be available in integration tests.
I wasn't able to use mockLogging in grails 1.3.7 with GrailsUnitTestCase either. I think there is probably a bug and it may work in Grails 2.0. Here is what I did to work around it:
class Foo {
String name
Long invokeLogTest(String key) {
if (key.empty) {
log.error("key was sent as empty string")
return 10
}
}
}
void testErrorCase() {
def f = new Foo(name:'jp')
f.metaClass.log = [error:{}]
assert 10 == f.invokeLogTest("")
}
Related
I am having issues while testing my grails controllers, as it depends on one service which seems not to be injected. I tried several ways (for ex. Extending classess like grailsunitestcase, specification) but I keep getting errors. The thing is that that service variable is null and I cant test my controller index method (which calls a render view) due to the exception...
I really need to know how to do this but I don't have a clue where to start...
Unit tests are just that. There is no grails 'environment' surrounding your controller. If the controller makes use of a service which is normally injected, you have to mock that service yourself.
#TestFor(SomeController)
#Mock([SomeService])
class SomeControllerSpec extends Specification
def "test some method"() {
given:
def mockService = mockFor(SomeService)
mockService.demand.someServiceMethod() { ->
return something
}
controller.someService = mockService.createMock()
when:
controller.someControllerMethod()
then:
// whatever checks are appropriate
}
}
I have a command object with a couple of static methods which access other domain objects.
static def isAValidSerial(String serialReference) {
return InventoryMaster.partSerialReferenceList(null, serialReference).size() > 0
}
This method is called by the validation constraints on the command object.
In a unit test I mock this behavior.
TransactionDetailCommand.metaClass.static.isAValidSerial = { String a -> println "mocked method called"; true }
before invoking some validation:
obj.validate(['serialReference'])
However this is throwing an exception where it didn't with 2.2.0.
The error is:
java.lang.IllegalStateException: Method on class [com.myStuff.MyClass] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
Despite the mocking when it's called from the validator it appears to be trying to invoke the real method and not the mock. If I put an explicit println before the obj.validate() it correctly prints the test text from the mocked method and returns the mocked value. This worked on 2.2 but now fails. I didn't used the grails update command. I created a new project and copied stuff to it. I've found various tips including removing the forked JVM stuff from the build config but nothing seems to work.
Anyone any ideas? Thanks.
I finally managed to get this working. Firstly I had to explicitly declare the collaborating class (InventoryMaster) within the #Mock annotation - on 2.2.n this wasn't required. Also when invoking mocked static methods from my validator I had to explicitly qualify the static call .. So what used to look like
if (!(cmdObj.transactionType.transactionIsAReceipt() || isAValidSerial(serialReference))) {
return 'TransactionDetailCommand.serialReference.not.found'
}
and work under 2.2.n had to be converted to ..
if (!(cmdObj.transactionType.transactionIsAReceipt() || TransactionDetailCommand.isAValidSerial(serialReference))) {
return 'TransactionDetailCommand.serialReference.not.found'
}
which kinda makes sense as I previously mocked the isAValidSerial using
TransactionDetailCommand.metaClass.static.isAValidSerial = {a -> println "running mock isAValidSerial -> true"; true }
Maybe that was 2.2.n being lax .. Anyway, my tests now work again !
I am using grails version 1.3.7. In my application in controller, I am making use of messages.properties and fetching the value of the property as
g.message(code:messageKey, args:msgParamsArr)
But when I started writing unit tests for the action in the controller, it gave me errors.
Please can you help me out to understand how to mock g.message exactly so that the existing code will fetch the message properties from messages.properties only.
You can mock it with:
controller.metaClass.message = { message ->
message.code
}
You can include message.args too if you want to just validate the arguments with .contains().
This works like a champ in Grails 2.4.5:
controller.metaClass.message = { Map attrs -> attrs.toString() }
I know there's a lot out there about this particular topic, however I can't quite find anyone who has stumbled across my issue, and hopefully someone can explain this to me.
I have a Domain where I use the injected grailsApplication's dynamic method 'isDomainClass' in the equals method:
#Override
public boolean equals(Object obj) {
if(!grailsApplication.isDomainClass(obj.getClass())) { return false }
...
}
This works fine, and to unit test this i do:
#Mock([MyDomain])
...
def mockGApp
void setUp() {
mockGApp = new Object()
mockGApp.metaClass.isDomainClass = { obj -> true }
}
...
void testSomething() {
def myDomain = new MyDomain()
myDomain.grailsApplication = mockGApp
....
}
And when I run this with test-app -unit (on command line or in STS) it passes just fine.
I then ave an integration test that uses that domain (no mocking this time) and that again runs fine when ran with test-app -integration (either on the command line or in STS)
However if i run 'test-app' so it does both at once, I get a MissingMethodException: no method signature isDomainClass exists with parameters (java.lang.Class) ... and all that jazz.
On investigating it with println's in the service I'm testing in the tests, in the integration portion of the testing, before the equals method of my domain class is called, I can quite happily call grailsApplication.isDomainClass() and get the desired affect. However when the code steps into the domain's equals function the isDomainClass() method no longer exists, despite the grailsApplication object referring to the same object which is referenced in the service and has the dynamically added method.
It appears that the dynamic methods that grails adds to this class are not being injected when its called within the domain's methods but are getting injected within the service. And more bizarrely this only happens if the integration tests follow the unit tests. If done separately, no problemo...
Where does this pollution stem from? IS there any way to solve it?
P.S. using Grails 2.1.0
You have to remove the class you modified from metaClassRegistry in the destroy method (i.e.after test case runs). See below:
#After
void destroy() {
GroovySystem.metaClassRegistry.removeMetaClass(MyDomain.class)
}
I am in the process of writing unit tests for a service class. This service class calls MyDomain.findAllByIdNotInList. The issue I am facing is that grails does not recognize NotInList as a dynamic finder for a mocked domain. I tried Metaclass-ing this functionality out, but was having issues with it.
Any creative ways for bypassing this short of turning the Unit Test into an Integration test? I would like to avoid this for multiple reasons (time to run, Only our Unit tests run at build time, etc)
Also, it is possible my metaclassing is written poorly:
MyDomain.metaClass.findAllByIdNotInList = {ArrayList list ->
return []
}
Edit: Using grails 1.3.7.
also tried
MyDomain.metaClass.findAllByIdNotInList = {deflist ->
return []
}
Bug report here:
http://jira.grails.org/browse/GRAILS-8593
#Sagar V's comment is correct you should be able to utilize all dynamic finders when a Domain is properly mocked. If you're using a version of Grails before 2.0 you'd have to extend GrailsUnitTestCase and call MockDomain(MyDomain) before attempting to invoke the dynamic finders. As an FYI your metaClassing is not written properly (in my opinion you should use the mocking framework to get your test working I'm providing the correct syntax so you can use it properly in the future).
MyDomain.metaClass.'static'.findAllByIdNotInList = {defList ->
[]
}
When the method that you're overriding is static you need to add the .'static'. inbetween the metaClass and the method name.