Mock testing in Grails 2.0 errors - grails

I've recently upgraded a Grails 1.3.7 project up to Grails 2.0.4 and noticed that many of my unit tests with mocking have started to fail. The Controller tests seem to pass just fine, the issue comes when you have Services collaborating with one another and try to mock out the calls to the collaborators. The strange part about it is if I run the single test, it passes, but as soon as I run the entire suite, they fail giving the error:
No more calls to 'getName' expected at this point. End of demands.
junit.framework.AssertionFailedError: No more calls to 'getName' expected at this point. End of demands.
I've even tried using GMock instead of new MockFor(), but get this very similar error:
No more calls to 'getSimpleName' expected at this point. End of demands.
junit.framework.AssertionFailedError: No more calls to 'getSimpleName' expected at this point. End of demands.
Here's a contrived example showing how to duplicate the errors I'm getting, and the entire sample project on GitHub at https://github.com/punkisdead/FunWithMocks. Any ideas of how to make this work?
BarController:
package funwithmocks
class BarController {
def barService
def fooService
def index() { }
}
BarService:
package funwithmocks
class BarService {
def fooService
def bazService
def serviceMethod() {
}
}
BarControllerTests:
package funwithmocks
import grails.test.mixin.*
import org.junit.*
import groovy.mock.interceptor.MockFor
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
#TestFor(BarController)
class BarControllerTests {
def fooService
def barService
#Before
public void setUp() {
fooService = new MockFor(FooService)
fooService.use {
controller.fooService = new FooService()
}
barService = new MockFor(BarService)
barService.use {
controller.barService = new BarService()
}
}
#Test
void doSomething() {
controller.index()
}
}
BarServiceTests:
package funwithmocks
import grails.test.mixin.*
import org.junit.*
import groovy.mock.interceptor.MockFor
/**
* See the API for {#link grails.test.mixin.services.ServiceUnitTestMixin} for usage instructions
*/
#TestFor(BarService)
class BarServiceTests {
def fooService
def bazService
#Before
public void setUp() {
fooService = new MockFor(FooService)
fooService.use {
service.fooService = new FooService()
}
bazService = new MockFor(BazService)
bazService.use {
service.bazService = new BazService()
}
}
#Test
void callSomeService() {
service.serviceMethod()
}
}

You shouldn't to combine the new test mixin with MockFor groovy class. Replace all MockFor instance with the mockFor method.
http://grails.org/doc/latest/guide/testing.html#mockingCollaborators

Related

How to mock service in groovy/src class under test with Grails 3.3.x

I've recently upgraded to grails 3.3.1 and realised that grails.test.mixin.Mock has been pulled to separate project which has been build just for backward compatibility according to my understanding org.grails:grails-test-mixins:3.3.0.
I've been using #Mock annotation to mock Grails service injected into groovy/src class under test. What is the tactic to mock collaborating services in this case? Is there anything from Spock what I can use or should I fallback to grails-test-mixins plugin?
Class under test:
import gra
ils.util.Holders
import grails.util.Holders
class SomeUtilClass {
static MyService myService = Holders.grailsApplication.mainContext.getBean("myService")
static String myMethod() {
// here is some code
return myService.myServiceMethod()
}
}
My test spec (Grails 3.2.1):
import grails.test.mixin.Mock
import spock.lang.Specification
#Mock([MyService])
class ValidatorUtilsTest extends Specification {
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Due to you use Holders.grailsApplication in your SomeUtilClass, you can try to add #Integration annotation:
import grails.testing.mixin.integration.Integration
import spock.lang.Specification
#Integration
class ValidatorUtilsTest extends Specification {
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Not sure, but hope it work for you.
Try with this code
#TestMixin(GrailsUnitTestMixin)
#Mock([your domains here])
class ValidatorUtilsTest extends Specification {
static doWithSpring = {
myService(MyService)
}
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Remove the #Mock annotation and implement ServiceUnitTest<MyService> in your test class.

How to get the spring bean instance of a service, added via dependency injection in webflow

I would like to mock a service method in an integration test for one test, however I don't know how to get a reference to the service as it's added to the controller via dependency injection. To further complicate things the service is in a webflow, but I know it's not stored in the flow as the service is not serialized.
Ideal mocking scenario:
Get reference to the service
Mock the method via the metaClass
Main test
Set the metaClass to null so it's replaced with the original
Methods like mockFor so far don't seem to effect the service.
Example of the setup:
Controller:
package is.webflow.bad
import is.webflow.bad.service.FakeService
class FakeController
{
def index = {
redirect(action: 'fake')
}
def fakeFlow = {
start {
action {
flow.result = fakeService.fakeCall()
test()
}
on('test').to('study')
}
study {
on('done').to('done')
}
done {
System.out.println('done')
}
}
}
Service:
package is.webflow.bad.service
class FakeService
{
def fakeCall()
{
return 'failure'
}
}
Test:
package is.webflow.bad
import static org.junit.Assert.*
import grails.test.WebFlowTestCase
import is.webflow.bad.service.FakeService
import org.junit.*
class FakeControllerFlowIntegrationTests extends WebFlowTestCase
{
def controller = new FakeController()
def getFlow() { controller.fakeFlow }
String getFlowId() { "fake" }
#Before
void setUp() {
// Setup logic here
super.setUp()
}
#Test
void testBasic()
{
startFlow()
assertCurrentStateEquals 'study'
assertEquals 'failure', getFlowScope().result
}
#Test
void testServiceMetaClassChange()
{
// want to modify the metaClass here to return success
startFlow()
assertCurrentStateEquals 'study'
assertEquals 'success', getFlowScope().result
}
}
You can inject the service into your Integration test using "#AutoWired" or using application context you get reference. Am i missing something?
#Autowired
private YourService yourservice;
or
#Autowired
private ApplicationContext appContext;
YourService yourService = (YourService)appContext.getBean("yourService");
Here you go:
void "test something"() {
given: "Mocked service"
someController.someInjectedService = [someMethod: { args ->
// Mocked code
return "some data"
] as SomeService
when: "Controller code is tested"
// test condition
then: "mocked service method will be called"
// assert
}

Integration test - how to test a method with no inputs and a render

How does one integration-test (Grails) a controller with no inputs and a render view? Here is my controller code and test; the test looks correct but throws a "java.lang.Exception: No tests found matching grails test target pattern filter" error. many thanks for your help. -ryan
Controller code section:
class ReportSiteErrorsController {
static allowedMethods = [reportError: 'GET', saveReportError: 'POST']
def mailService
#Transactional(readOnly = true)
def reportError() {
render(view:'reportError', model:[])
}
}
Integration Test:
#TestFor(ReportSiteErrorsController)
class ReportSiteErrorsControllerTests extends DbunitGroovyTestCase {
#Test
void "test report error"() {
controller.reportError()
assert view == "reportError"
}
}
Leave the extension off in your command line. You are supposed to be specifying the name of the test, not the name of the file in which it is defined.
Use something like...
grails test-app integration: NameOfTest
Not something like...
grails test-app integration: NameOfTest.groovy
I hope that helps.
in Grails 2.4 the default syntax to test render "hello" would be:
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
#TestFor(SimpleController)
class SimpleControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
controller.index()
expect:
response.text == "hello"
}
}
The assert won't do for me. See also: the Grails Documentation

Grails Fixtures / Build Test Data plugin not working within a Unit Test

I am trying to use the Grails Fixtures Plugin within a service unit test. I am using grails 2.2.
I have the next code in my BuildConfig.groovy
plugins {
compile ":fixtures:1.2"
compile ":build-test-data:2.0.3"
...
..
.
}
Initially I tried
#TestFor(HotelService)
#Mock([Place])
class HotelServiceTests {
def fixtureLoader
void testFixturesInUnitTests() {
def fixture = fixtureLoader.build {
hotel(Place, name: "Hotel Hilton")
}
}
}
The above test was failing:
| java.lang.NullPointerException: Cannot invoke method build() on null object
With a Google Search I found in the Grails User Mailing List that the fixtureLoader have to createdexplicitly inside the unit test.
import grails.plugin.fixtures.*
#TestFor(HotelService)
#Mock([Place])
class HotelServiceTests {
def fixtureLoader
def grailsApplication
#Before
void setUp() {
fixtureLoader = new FixtureLoader(grailsApplication)
}
void testFixturesInUnitTests() {
def fixture = fixtureLoader.build {
hotel(Place, name: "Hotel Hilton")
}
}
}
Test failed with the next error:
java.lang.NullPointerException: Cannot invoke method hasGrailsPlugin() on null object
at grails.plugin.fixtures.builder.FixtureBuilder.lookForBuildTestDataPlugin(FixtureBuilder.groovy:53)
at grails.plugin.fixtures.builder.FixtureBuilder.<init>(FixtureBuilder.groovy:49)
at grails.plugin.fixtures.Fixture.createBuilder(Fixture.groovy:75)
at grails.plugin.fixtures.Fixture.build(Fixture.groovy:44)
at grails.plugin.fixtures.FixtureLoader.build(FixtureLoader.groovy:46)
Another GoogleSearch and I found a 'hack' to avoid the previous error.
import grails.plugin.fixtures.*
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.codehaus.groovy.grails.plugins.PluginManagerHolder
#TestFor(HotelService)
#Mock([Place])
class HotelServiceTests {
def fixtureLoader
def grailsApplication
#Before
void setUp() {
fixtureLoader = new FixtureLoader(grailsApplication)
PluginManagerHolder.pluginManager = [hasGrailsPlugin: { String name -> true }] as GrailsPluginManager
}
void testFixturesInUnitTests() {
def fixture = fixtureLoader.build {
hotel(Place, name: "Hotel Hilton")
}
}
}
Now I am getting the next error:
java.lang.NullPointerException: Cannot invoke method isDomainClass() on null object
at grails.plugin.fixtures.buildtestdata.BuildTestDataBeanDefinitionTranslator.translate(BuildTestDataBeanDefinitionTranslator.groovy:54)
at grails.plugin.fixtures.buildtestdata.BuildTestDataBeanDefinitionTranslator.translate(BuildTestDataBeanDefinitionTranslator.groovy:43)
at grails.plugin.fixtures.builder.FixtureBuilder.translateToBuild(FixtureBuilder.groovy:126)
at grails.plugin.fixtures.builder.FixtureBuilder.invokeMethod(FixtureBuilder.groovy:121)
at com.softamo.movilrural.TopRuralScraperServiceTests$_testFixturesInUnitTests_closure2.doCall(TopRuralScraperServiceTests.groovy:26)
I have no idea how to solve this. Any feedback is really welcome.
The fixtureLoader.build() method integrates with the Build Test Data plugin. The fixtures plugin is intended to be used in conjunction with integration tests.
See also this issue http://jira.grails.org/browse/GPFIXTURES-21.
The #TestFor annotation marks test as unit, so you need to remove it.
File /test/integration/com.example/HotelServiceTests.groovy
class HotelServiceTests extends GroovyTestCase {
FixtureLoader fixtureLoader
Fixture fixture
void setUp() {
fixture = fixtureLoader.load {
build {
hotel(Place, name: "Hotel Hilton")
}
}
}
void testFixturesInUnitTests() {
// given:
HotelService service = new HotelService()
// when:
List<Place> hotels = service.list()
// then:
assert hotels.size() == 1
assert hotels[0] == fixture.hotel
}
}
Hope it helps you.
I'm not really an expert on fixture loader, but it seems you're just calling the wrong method (build instead of load).
#TestFor(HotelService)
#Mock([Place])
class HotelServiceTests {
def fixtureLoader
void testFixturesInUnitTests() {
def fixture = fixtureLoader.load {
hotel(Place, name: "Hotel Hilton")
}
}
}
I haven't tried it, but you can look at the fixtures loader usage here: Grails Fixtures Plugin - Reference Documentation
There is not really a way to support the use of fixtures plugin in a Grails Unit test.
You can achieve the same goals by using BuildTestData plugin, which provides the #Build annotation which supports the UnitTests.

Testing Service in Grails produces 'org.junit.ComparisonFailure: expected:<An[a]nymous> but was:<An[o]nymous>' error

I'm working my way through 'Grails in Action' and I'm running into an issue when trying to write an Integration test for one of my services.
I realize that I'm using Grails 2.0.3 whereas the book was written with Grails 1.x.x in mind.
Here is my Service:
package qotd
class QuoteService {
boolean transactional = true
def getRandomQuote(){
def allQuotes = Quote.list()
def randomQuote
if(allQuotes.size() > 0){
def randomIndex = new Random().nextInt(allQuotes.size())
randomQuote = allQuotes[randomIndex]
}
else{
randomQuote = getStaticQuote()
}
return randomQuote
}
def getStaticQuote(){
return new Quote(author: "Anonymous",
content: "Real Programmers Don't eat quiche")
}
}
And below is my Integration Test, located in '/test/integration/qotd/'
package qotd
import static org.junit.Assert.*
import org.junit.*
class QuoteServiceIntegrationTests extends GroovyTestCase {
def quoteService
#Before
void setUp() {
}
#After
void tearDown() {
}
#Test
void testStaticQuote() {
def staticQuote = quoteService.getStaticQuote()
assertNotNull quoteService
assertEquals "Ananymous",staticQuote.author
assertEquals "Real Programmers Don't Eat Quiche",staticQuote.content
}
}
Just in case it may be relevant, here is the Quote class that I'm testing the contents of above:
package qotd
class Quote {
String content
String author
Date created = new Date()
static constraints = {
author(blank:false)
content(maxSize:1000,blank:false)
}
}
When I run my test, using 'test-app -integration' I get the following:
Running 1 integration test... 1 of 1
Failure: testStaticQuote(qotd.QuoteServiceIntegrationTests)
org.junit.ComparisonFailure: expected: An[a]nymous but was:An[o]nymous
at org.junit.Assert.assertEquals(Assert.java:125)
at org.junit.Assert.assertEquals(Assert.java:147)
at qotd.QuoteServiceIntegrationTests.testStaticQuote(QuoteServiceIntegrationTests.groovy:24)
Any insight would be appreciated. Thank you all!
you spelled "Anonymous" incorrectly on this line
assertEquals "Ananymous",staticQuote.author

Resources