I have controller with following code:
def profile = Profile.findByProfileURL(params.profileURL)
and unit test like this:
#TestMixin(GrailsUnitTestMixin)
#TestFor(ProfileController)
#Mock([User])
class ProfileControllerTests {
def void testIndex() {
mockDomain(User, [[firstname: 'Niko',...]])
controller.params.profileURL = 'niko-klansek'
controller.index()
...
}
}
When I run the test I get following exception in the controller referring to :
No signature of method: sportboard.core.profile.Profile.methodMissing() is applicable for argument types: () values: []
So params value profileURL that I have set in the test is not visible from the controller? How can I set params for controller so it is visible?
Exception is cryptic, but it says that your Profile domain class is not mocked. You should add it to #Mock annotation. Also, #TestMixin can be ommited here and you shouldn't use mockDomain directly in test. Just save this user instance. Altogether it should look like this:
#TestFor(ProfileController)
#Mock([User, Profile])
class ProfileControllerTests {
def void testIndex() {
def user = new User(firstName: 'Niko').save()
controller.params.profileURL = 'niko-klansek'
...
}
}
Related
I can mock a function of a to be tested class in several ways. But how do I mock an object that is created inside of a to be tested method?
I have this to be tested class
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
import groovyx.net.http.HTTPBuilder
class totest {
def get() {
def http = new HTTPBuilder('http://www.google.com')
def html = http.get( path : '/search', query : [q:'Groovy'] )
return html
}
}
How do I mock http.get so I can test the get function:
class TestTest extends Specification {
def "dummy test"() {
given:
// mock httpbuilder.get to return "hello"
def to_test = new totest()
expect:
to_test.get() == "hello"
}
}
A better approach would be to pass the HTTPBuilder into your constructor and then the test code can pass test mocks instead.
But if you want to mock the class construction going on internal to your code, have a look at mocking constructors and classes using GroovySpy and GroovyMock on here: http://spockframework.org/spock/docs/1.0/interaction_based_testing.html
You would need to do something like the below code:
import spock.lang.Specification
import groovyx.net.http.HTTPBuilder
class totest {
def get() {
def http = new HTTPBuilder('http://www.google.com')
def html = http.get( path : '/search', query : [q:'Groovy'] )
return html
}
}
class TestTest extends Specification{
def "dummy test"() {
given:'A mock for HTTP Builder'
def mockHTTBuilder = Mock(HTTPBuilder)
and:'Spy on the constructor and return the mock object every time'
GroovySpy(HTTPBuilder, global: true)
new HTTPBuilder(_) >> mockHTTBuilder
and:'Create object under test'
def to_test = new totest()
when:'The object is used to get the HTTP result'
def result = to_test.get()
then:'The get method is called once on HTTP Builder'
1 * mockHTTBuilder.get(_) >> { "hello"}
then:'The object under test returns the expected value'
result == 'hello'
}
}
What are you testing here? Do you care how the method gets it's result? Surely you care more that it gets the right result? In that case, the method should be changed so the URL is configurable, then you can stand up a server that returns a known string, and check that string is returned
So we have a restful service that we want to test using a restclient in grails.
The test code should go something like this...
class MyControllerSpec extends Specification {
def setup() {
this.dbEntity = new DbEntity("someid123").save();
}
void "Test entity GET"{
given:
RestBuilder rest = new RestBuilder()
when: "The DB entity service is hit"
RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$id");
then: "A 200 error is sent"
restResponse.status == 200
}
The problem I am having is the setup method blows up on .save() because there is not hibernate session. How can I manipulate my database before running a test?
You can define a method named like "setupData", and call it in the "given" block of "Test entity GET" testcase.
def setupData() { this.dbEntity = new DbEntity("someid123").save(); }
If you need to load some data before each funcional test, you can create a helper class, with #Shared variables or methods or both. Even you could override the setup, setupSpec methods in that class.
Your first class does not extends Specification now, DataLoader class (helper class) instead.
class MyControllerSpec extends DataLoader {
void setup(){
createEntity()
}
void "Test entity GET"{
given:
RestBuilder rest = new RestBuilder()
when: "The DB entity service is hit"
RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$dbEntity.id");
then: "A 200 error is sent"
restResponse.status == 200
}
}
And your helper class is the one which extends Specification, with its methods and #Shared variables.
import spock.lang.Shared
class DataLoader extends Specification {
#Shared DbEntity dbEntity
void createEntity(){
dbEntity = new DbEntity("someid123").save();
}
}
When extending GebSpec in Grails 2.5.6, none of the other answers helped: I would still get
Method on class [...] was used outside of a Grails application
on the save() call.
Adding #TestFor(DbEntity) to the test class helped.
NB: While that annotation breaks integration tests, it seems to be necessary here. Not sure why that is.
You probably want to use the remote-control plugin. In Grails 2.x, add this to your BuildConfig.groovy:
repositories {
...
mavenRepo "http://dl.bintray.com/alkemist/maven/"
}
plugins {
...
test ":remote-control:2.0"
}
After refreshing dependencies and potentially adjusting some settings (see e.g. here and here), you can use it like so in tests:
// <project>/test/functional/<package>/MyControllerSpec.groovy
class MyControllerSpec extends GebSpec {
RemoteControl remote
DbEntity dbEntity
def setup() {
this.remote = new RemoteControl()
this.dbEntity = remote {
new DbEntity("someid123").save()
}
}
def cleanup() {
remote {
DbEntity.findAll().each { dbe ->
println("Deleting $dbe")
dbe.delete()
}
}
}
Note:
You can invoke remote in given/setup and when blocks as well.
Sometimes, it seems to be necessary to wrap core in remote { ... } in a DbEntity.withTransaction { ... }. Maybe that's obvious for the more intitiated; I stumbled over that.
If you want to return a DbEntity from remote it must be serializable.
Using Spock framework for java unit testing.
When unit testing a method method1() and method1 is calling a method method2(),In method2() having a code statement as below :
Config config = new Config();
TimeZone tz=TimeZone.getTimeZone(config.getProps().getProperty(Constants.SERVER_TIMEZONE));
The call config.getProps().getProperty(Constants.SERVER_TIMEZONE)
returns America/Cambridge_Bay
In getProps method the property files is fetched from weblogic domain and it will not be available in spcok, its taking path as null.
Please suggest how can this function call be mocked in spock.
We can use meta class injection to mock response method2 in unit testing given block. Here ClassName is the class to which method2 belongs to.
ClassName.metaClass.method2 = { inputParameters ->
return "America/Cambridge_Bay"
}
Also it is advisable to use #ConfineMetaClass([ClassName]) annotation on the unit test to confine the meta class injection changes to your test case.
Lets start with an example which simulates your situation:
class Config {
Properties getProps() {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'America/Cambridge_Bay')
props
}
}
class Constants {
static String SERVER_TIMEZONE = 'TIMEZONE'
}
Config config = new Config()
def timeZoneID = config.getProps().getProperty(Constants.SERVER_TIMEZONE)
def tz = TimeZone.getTimeZone(timeZoneID)
assert tz.ID == 'America/Cambridge_Bay'
Since method2() doesn't get a Config instance injected into it, mocks are out of the question. So we'll use Groovy's metaClass, at the class level (since instance level is out of the question too, for the same reason). You can override Config.getProps() like this:
Config.metaClass.getProps {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'Etc/UTC')
props
}
So you can write your Spock test roughly like this:
// import Constants
// import Config class
class FooSpec extends Specification {
#ConfineMetaClassChanges
def "test stuff"() {
when:
Config.metaClass.getProps {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'America/Cambridge_Bay')
props
}
// Do more stuff
then:
// Check results
}
}
PS
If you can modify method2() to have Config injected, that would be preferable since then you can use Groovy's MockFor.
I am trying to write unit test case for grails controller which has following structure:
class MyController{
def save(){
def myDomain = new MyDomain(params)
business validation 1
business validation 2
myDomain.writedatasource.save()
business validation 3
business validation 4
}
}
Since Unit test doesn't load Datasource.groovy the writedatasource isn't available during unit testing so the test cases for "business validation 3" and "business validation 4" fail as I get
groovy.lang.MissingPropertyException: No such property: writedatasource for class: MyDomain
How can I modify my test case to test validation scenarios 3 and 4?
Test case is simple and looks like follows:
void testSave(){
...setup...
controller.save()
assert conditions
....
}
Not sure if that could make the trick, but you can try:
def 'the controller call the save method in writedatasource'() {
given:
def calls = 0
and:
def myDomainInstance = new MyDomain()
and:
MyDomain.metaClass.getWritedatasource = { new Object() }
and:
Object.metaClass.save = { Map attrs ->
calls++
}
when:
controller.save()
then:
calls == 1
}
But the only thing are you doing is testing that the save is called under writedatasource, so it would be better to have also an integration test. If that makes the trick, please answer as well at http://grails.1312388.n4.nabble.com/Mocking-in-a-unit-test-a-domain-object-multiple-datasources-td4646054.html as they seem to have the same problem.
Addressing original question:
I ran into this and would have had to mock many, many more methods than just 'save' on multiple domains. So instead, I overrode the getter of my domains to simply return the invoking domain instance:
def setup() {
[MyDomain1, MyDomain2].each { Class clazz ->
mockDomain(clazz)
clazz.metaClass.getWritedatasource = {
return delegate
}
clazz.metaClass.'static'.getWritedatasource = {
return delegate
}
}
}
This also saves me from including #DirtiesRuntime since I'm not updating the metaClass of anything I'd want to clean.
Most importantly, whatever calls the datasource, be it the domain class or the instance, it should be decorated with GORM fanciness from mockDomain, meaning I don't have to mock any of the GORM methods.
What if you want dynamic datasources?
In my particular case, datasources are configurable and may change depending on environment. If you're in a similar situation, you can configure this in your domain mapping:
static mapping = {
datasources Holders.grailsApplication?.config.dynamic?.datasources
...
}
where dynamic.datasources is an array of datasource names. Then, in the test setup:
def setup() {
grailsApplication.config.dynamic.datasources = ['foo', 'bar']
[MyDomain1, MyDomain2].each { Class clazz ->
mockDomain(clazz)
grailsApplication.config.dynamic.datasources.each{
clazz.metaClass."get${it.capitalize()}" = {
return delegate
}
clazz.metaClass.'static'."get${it.capitalize()}" = {
return delegate
}
}
}
}
In my grails application, in the controller, I use following kind of a thing :
class SampleController {
def action1 = {
def abc = grailsApplication.getMetadata().get("xyz")
render abc.toString()
}
}
While running the app, it correctly reads the property "xyz" from application.properties and works fine. But when I write a unit test case for the above controller as follows :
class SampleControllerTests extends ControllerUnitTestCase {
SampleController controller
protected void setUp() {
super.setUp()
controller = new SampleController()
mockController(SampleController)
mockLogging(SampleController)
}
void testAction1() {
controller.action1()
assertEquals "abc", controller.response.contentAsString
}
}
But when I do "grails test-app", I expect that it will pick up the property "xyz" from application.properties and will return as expected. But it gives error as "No such property : grailsApplication".
I understand, I guess I need to mock grailsApplication object and I tried many of the options also But all those didn't work.
I am new to Grails.
mockController will not mock the GrailsApplication, you will need to do it yourself.
The fastest solution would be something like:
protected void setUp() {
super.setUp()
mockLogging(DummyController)
GrailsApplication grailsApplication = new DefaultGrailsApplication()
controller.metaClass.getGrailsApplication = { -> grailsApplication }
}
This solution is not perfect - it will create a new DefaultGrailsApplication during each setup and mockController also creates some additional instances of DefaultGrailsApplication.
Note that you do not need to call mockController by yourself it will be done by the ControllerUnitTestCase for you.