Grails test failing on view - grails

I'm a pretty raw Grails newb but I know some Groovy and I have a Java background. This is an ancient test app I'm updating to Java 8 from Java 6.
Context: Grails 2.3.9 / Java 1.8.0_101
The test that is failing is:
#TestFor(PillsController)
#Mock(Pills)
class PillsControllerTests {
...
void testUpdate() {
controller.update()
assert flash.message != null
assert response.redirectedUrl == '/somethingPills/list'
response.reset()
populateValidParams(params)
def somethingPills = new SomethingPills(params)
assert somethingPills.save() != null
params.id = somethingPills.id
controller.update()
assert view == "/somethingPills/edit" //<--- FAILS HERE. VIEW IS NULL.
assert model.somethingPillsInstance != null
somethingPills.clearErrors()
populateValidParams(params)
controller.update()
assert response.redirectedUrl == "/somethingPills/show/$somethingPills.id"
assert flash.message != null
response.reset()
somethingPills.clearErrors()
populateValidParams(params)
params.id = somethingPills.id
params.version = -1
controller.update()
assert view == "/somethingPills/edit"
assert model.somethingPillsInstance != null
assert model.somethingPillsInstance.errors.getFieldError('version')
assert flash.message != null
}
}
I assume "view" is a reference to some codified variant of Model/View/Controller.
I found the update at the top confusing. Update what if nothing has been saved? I tried moving populate and SomethingPills declaration above update. The result was that view was still null. How can I predict what view will be?
Another thing I noticed. If I click on the update method, I see that there are two parameters. I'm assuming that Groovy allows you pass no parameters by default or I would be seeing an error about that. I don't know if this is how it is supposed to work but if I pull the ID & version from SomethingPills and pass them then I get /somethingPills/show/1" instead of null but still not "/somethingPills/edit".
[EDIT] I've found this: http://docs.grails.org/2.3.9/guide/scaffolding.html

Go to your PillsController.groovy file and find the update() method.
See if you have a statement like
render view:'/somethingPills/edit', ....
In the unit test, view refers to the path of the gsp file that the controller renders.
I am pretty sure there would be some logic in the update() method, which you need to post if the unit test still fails. Form the unit test, it looks like as if some condition matches, then it renders the gsp template otherwise it redirects.

Related

Validating call arguments with a closure when stubbing return value

I have a question about validating arguments in a mock call with a closure. Sometimes I do this:
customerRepository.save({ Customer customer ->
assert ...
assert ...
}) >> { ... some return value ... }
etc. i.e. multiple (but not too many) asserts in the closure, and also want to stub the call to return something. What I found out is that the code above doesn't work, I need to return a truthy value from the closure, otherwise the object I want to return is not returned and the test will fail somewhere else.
I don't think this is documented, could anybody say what the rules here are exactly?
Edit: actually, I've just checked and I need to return a truthy value even if I don't stub the return value.
So far i know two options for validating arguments. Either match the arguments in-place which does not require asserts:
then:
1 * customerRepository.save({ it.id == 1 && it.name == "joe" }) >> returnValue
However, this will give you "too few invocations" if the validation fails which I find misleading in some cases and usually harder to debug.
Alternatively, match all arguments and assert in the implementation:
then:
1 * customerRepository.save(_) >> { Customer customer ->
assert customer.id == 1
assert customer.name == "joe"
return returnValue
}
This will give you very descriptive assertion errors.

WithNewWindow() returns MultipleCompilationErrorsException in Geb

I am getting weird error in my geb functional tests.
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Spec expression: 1: expecting '}', found 'assert' # line 1, column 71.
} ) { at(JobOfferDetailPage) assert des
My test looks like this. I click on a link which opens a new window with details of the job offer. Than I want to assert some text on the new page using Page Pattern.
Test:
withNewWindow( { quickShowOption.click() } ) { //TODO fix me
at(JobOfferDetailPage)
assert description.text() == 'some text'
assert requirements.text() == 'some text'
assert advatages.text() == 'some text.'
assert categories.text() == 'some text'
assert locality.text() == 'some text'
}
Page:
class JobOfferDetailPage extends Page {
static at = {$('#contactLabel').text() == 'Contact'}
static content = {
description {$('#jobOfferDescription')}
requirements {$('#jobOfferRequirements')}
advatages {$('#jobOfferAdvantages')}
jobOfferType {$('#jobOfferType')}
categories {$('#categories')}
locality {$('#locality')}
startDate {$('#startDate')}
requiredLanguages {$('#requiredLanguages')}
}
}
I get compilation error after my conditions are asserted. If I make a typo in asserted text than the test will fail normally, but if it passes, than it fails with this weird error.
Thank you #Erdi.
I use spock,geb versions "0.13.1" and selenium version "2.51.0".
If one was to believe this comment in one of Geb's own tests, which was nota bene written by me some time ago, this indeed seems like some sort of bug in Spock. What is interesting is that I just now moved that statement to an expect block and it works as long as the last statement in the second closure passed to newWindow() evaluates to true. This makes me think that it is an issue with old version of Spock and/or Groovy. Which versions of the aforementioned tools are you using?
One possible workaround would be to move your statement from expect/then to one that is not asserting (given or when) as shown in the test I linked to.

Grails spock service test not calling service method

I'm seeing some strange behavior in a spock test for a service using Grails 2.3.7.
This test works fine:
void "create spot order"() {
given:
def createOrderCommand = newCreateOrderCommand(OrderType.S)
when:
def orderId = service.createOrder(createOrderCommand, user).id.toInteger()
then:
Order.count() == 1
when:
def order = service.orderById(orderId)
then:
// a bunch of assertions
}
This test also works fine:
void "create command with invalid order id"() {
when:
service.commandForOrderId(999)
then:
def exception = thrown(CreateOrderException)
exception.key == "orderService.invalid.order.id"
}
However this test fails - I've set a breakpoint at the beginning commandForOrderId, and it is never hit. command is null (this is where the test fails, on the line checking for null on command), which would never be returned from this service method:
void "create spot command"() {
given:
def createOrderCommand = newCreateOrderCommand(OrderType.S)
when:
def order = service.createOrder(createOrderCommand, user)
then:
Order.count() == 1
when:
def orderId = order.id.toInteger()
def command = service.commandForOrderId(orderId)
then:
command
// a bunch more assertions
}
I've tried removing the #Transactional annotation from the service, using the transactional static field, as well as using neither of these. I've also tried changing the service method to a closure, all with no luck.
I changed the service method to a closure, cleared my target directories, did every manner of clean I know of (within GGTS and grails commands), and the service method started getting hit in the test. I'm still unsure of the actual cause of this error, however.

What is wrong with my Spec?

So, I have this pretty simple Spec below. I have a class that is not a controller or service or anything like that. It's a Job class. It depends on two services: updateService and directoryTypeService. It runs a Redis async job and it's under /grails-app/jobs folder.
All I want is to make sure that whenever I invoke this job#perform() method (which return type is void), a given dependent method called UpdateService#completeClaiming is invoked, but UpdateService#requestNewPin is not. (Listing is a domain class, by the way).
When I run this Spec, I keep getting an error message saying: "No more calls to 'completeClaiming' expected at this point. End of demands."
What am I doing wrong here? Any wild guesses?
#Mock(Listing)
class SubmissionJobSpec extends Specification {
def directoryTypeServiceMock
def updateServiceMock
def job
def setup(){
job = new SubmissionJob()
directoryTypeServiceMock = mockFor(DirectoryTypeService)
updateServiceMock = mockFor(UpdateService)
job.updateService = updateServiceMock.createMock()
job.directoryTypeService = directoryTypeServiceMock.createMock()
}
def "if the directory is enabled and the pin status is ENTERED, we should call updateService.completeClaiming"() {
given:
directoryTypeServiceMock.demand.isUpdateEnabled { DirectoryType d, Country c -> return true}
new Listing(
location: new Location(country: Country.DE)
).save(failOnError: true, validate: false)
when:
job.perform(Listing.last().id, true)
then:
1 * updateServiceMock.completeClaiming(Listing.last(), true) >> new ListingEvent(output: [success: true])
0 * updateServiceMock.requestNewPin(_ as Listing, true)
}
You seem to be confusing Groovy and Spock mocks. You can't use Spock mocking syntax (e.g. 0 * updateServiceMock.requestNewPin(_ as Listing, true)) for a Groovy mock created with mockFor(). Spock mocks are created using Mock(), Stub() or Spy(). I'm not aware of any good reason to use a Groovy mock in a Spock spec.

Replace a method with parameters by a closure in metaclass

I have two class:
class Foo {
String doSomething(String a, String b) {
return 'Not Working'
}
}
class Bar {
String methodIWannaTest() {
return new Foo().doSomething('val1', 'val2')
}
}
And I want to replace 'doSomething' in a test but it dosent work
class BarTests {
#Test
void testMethodIWannaTest() {
Foo.metaClass.doSomething {String a, String b -> return 'Working'}
assert new Bar().methodIWannaTest() == 'Working' //THIS TEST FAIL, return 'Not Working'
}
}
*I know the test doesn't really make sens, it's just to show my point
What do I do wrong ? Is it possible to do it without using 'mockFor' ?
I would suggest you to start the test afresh. Baby Steps is what I follow. :)
Create a new grails app.
Create both Foo and Bar inside src/groovy under a package.
Create unit test case from command prompt. Put the desired test code.
Execute grails test-app
[Grails v2.2.0]
Another alternative is to use Groovy MockFor.
def mock = MockFor(Foo)
mock.demand.doSomething = {String a, String b -> return 'Working'}
mock.use {
assert new Bar().methodIWannaTest() == 'Working'
}
A downside is that there was a bug, making unit tests not clear the mock. This is fixed for 2.2.3.
I found the problem:
First, in my exemple, I forgot the '=' when defining the closure
Foo.metaClass.doSomething {String a, String b -> return 'Working'}
should be
Foo.metaClass.doSomething = {String a, String b -> return 'Working'}
While searching I also found that you cannot replace a method with optionnal parameters by a closure. Probably a bug
I tried this on GGTS 3.2.0 and got the following results.
Copied all the code and ran on Grails 2.2.2: everything worked correctly. However, then I commented out Foo.metaClass.doSomething = {String a, String b -> return 'Working'} line and, surprisingly, the test was still passing successfully. I did more changes and the metaClass just seemed to get "cached" between tests: changes had no effect.
Then I thought if it is possible that Grails were running in interactive mode. Went to Preferences > Groovy > Grails > Grails Launch and found a checkbox 'Keep external Grails running' ticked. Its tooltip even has the following words: 'Warning: experimental feature!'. Unticking that checkbox did the trick and the metaClass no longer got cached between test runs. I am still wondering why an exprimental feature would be turned on by default...

Resources