I am using GebReportingSpec.
I want to get name of test that will be executed by using setup method.
I am get null output from testName.methodName
my code snippet is as below:
class CRMAppLoginSpec extends GebReportingSpec {
#Rule
public TestName testName = new TestName()
setup()
{
String methodName = testName.methodName;
println (methodName)
}
def "mytest"(String myName)
{
given: "This is my test case in geb-spock"
when: "capture the parameter"
def var1 = myName
then: "Display input parameter"
println ("Welcome to geb-spock : ${var1}" )
where:
myName << ["Debasish", "Prashant"]
}
You should probably start with code that runs.
Check out this answer about working with errors on each test, it will show you how to do something at each phase of the test lifecycle. Answer
If you are trying to improve console reporting it would be best to use Spock's AbstractRunListener. Check this out
You have iterations where each method name will be identical you could use the #Unroll annotation to differentiate between them.
class TestSpec extends GebReportingSpec {
#Rule
public TestName testName = new TestName()
def setup() {
String methodName = testName.methodName;
println(methodName)
}
#Unroll("Iteration: mytest #myName")
def "mytest"() {
given: "This is my test case in geb-spock"
when: "capture the parameter"
then: "Display input parameter"
println("Welcome to geb-spock : ${myName}")
where:
myName << ["Debasish", "Prashant"]
}
}
Related
This is specific to Jenkins but hoping there is a generic groovy feature that can help me here.
I have a groovy script (myCustomStep.grooy) I want to unit test. It MUST be written like it is below (it cannot be a class). It will include methods that are available during Jenkins run time but not locally and I want to mock them out.
Here is one of these scripts and a corresponding test. How do I mock out echo without modifying myCustomStep.groovy?
# vars/myCustomStep.grooy
def call(Map config) {
def paramOne = config.paramOne
echo paramOne
}
class MyCustomStepTest {
// I tried to define it here but I get "No signature of method: myCustomStep.echo()"
def echo(message) {
println "$message"
}
#Test
public void "sdfsdfsdf"() throws Exception {
def aaa = new GroovyShell().parse( new File( 'vars/myCustomStep.groovy' ) )
aaa deployment: "sdlfsdfdsf"
}
}
I can't have myCustomStep.grooy accept echo as an argument. Is there a way to monkey patch echo into the myCustomStep namespace?
EDIT: I found a simple solution but now I want to know how I can attach methods to myCustomStep for all tests instead of having to redefine for every test. I tried to do this in a #Before method (using junit) but the myCustomStep obj wasn't available to the tests.
class MyCustomStepTest {
def myCustomStep = new GroovyShell().parse( new File( 'vars/myCustomStep.groovy' ) )
#Test
public void "sdfsdfsdf"() throws Exception {
// how can I attach this once for use by all my tests?
myCustomStep.echo = { String message -> println "$message" }
myCustomStep deployment: "sdlfsdfdsf"
}
}
EDIT:
I was just confused about where to instantiate the object. Looks like I just need to create the object outside of the #before method and then update it inside of it.
#Before
public void setUp() throws Exception {
myCustomStep.echo = { String message -> println "$message" }
}
def myCustomStep = new GroovyShell().parse( new File( 'vars/myCustomStep.groovy' ) )
You could put echo in the binding using something like this:
Binding b = new Binding()
b.echo = { println "Hello There" }
def shell = new GroovyShell(b)
def aaa = shell.parse( new File( 'ars/myCustomStep.groovy' ) )
aaa deployment: "sdlfsdfdsf"
When do grails unit test with Spock, can't auto inject a service instance to domain.
Below is my code.
Service:
class HiService {
public HiService(){
println "Init HiService," + this.toString()
}
def sayHi(String name){
println "Hi, ${name}"
}
}
Domain:
class User {
public User(){
if (hiService == null){
println "hiService is null when new User(${name})"
}
}
String name
def hiService
def sayHi(){
println "Before use hiService " + hiService?.toString()
hiService.sayHi(name)
println "End use hiService" + hiService?.toString()
}
}
TestCase:
#TestFor(HiService)
#Mock([User])
class HiServiceTest extends Specification {
def "test sayHi"() {
given:
def item = new User( name: "kitty").save(validate: false)
when: "Use service method"
item.sayHi()
then : "expect something happen"
assertEquals(1, 1)
}
}
The following was console log:
--Output from test sayHi--
Init HiService,test.HiService#530f5e8e
hiService is null when new User(null)
Before use hiService null
| Failure: test sayHi(test.HiServiceTest)
| java.lang.NullPointerException: Cannot invoke method sayHi() on null object
at test.User.sayHi(User.groovy:17)
at test.HiServiceTest.test sayHi(HiServiceTest.groovy:20)
The service initialized, but can't inject to domain. But when run app directly, service will auto-inject to domain
If you wan't autowiring it needs to be an integration test. If using Grails 3 then annotate with #Integration, if grails 2 then extend IntegrationSpec.
See: http://docs.grails.org/latest/guide/testing.html#integrationTesting
#Mock([User, HiService])
class HiServiceTest extends Specification {
def "test sayHi"() {
// ....
}
}
Since you are writing unit tests, your service will not be autowired. Also as you are unit testing the User class object, you should write the test in UserSpec (instead of UserServceTest; Suffixing Spec is the convention in Spock). Now you can mock the HiService instead like this:
class UserSpec extends Specification {
def "User is able to say hi"() {
given:
User user = new User(name: 'bla bla')
and: "Mock the user service"
def hiService = Mock(HiService)
user.hiService = hiService
when:
user.sayHi()
then:
1 * sayHiService.sayHi(user.name)
}
}
Service:
#GrailsCompileStatic
class MyService {
final static String PLACEHOLDER = '<x>'
#Value('${myService.url}') // Suppose it http://example.com/doc-<x>.html
private String urlTemplate
String getSomeUrl(String lang) {
urlTemplate.replace(PLACEHOLDER, lang)
}
}
Unit test:
#TestFor(MyService)
class MyServiceSpec extends Specification {
#Unroll
void "test get some url for #lang"() {
when:
def someUrl = service.getSomeUrl(lang) // NullPointerException, because urlTemplate is null
then:
someUrl.endsWith(lang + '.html')
where:
lang << ['es', 'en']
}
}
So, as I mentioned above, urlTemplate is null (but config value exists in .properties). How to fix it?
Solution:
class MyServiceSpec extends IntegrationSpec {
MyService myService
#Unroll
void "test get some url for #lang"() {
when:
def someUrl = myService.getSomeUrl(lang)
then:
someUrl.endsWith(lang + '.html')
where:
lang << ['es', 'en']
}
}
Unit tests are used to test isolated units of code. If you are testing behavior that is dependent on the configuration value, inject it into the unit test to achieve reusable unit tests.
On the other hand, if you are testing that the variable is actually set or what the variable is set to, you need to use an integration test because you are basically testing your integration with Grails' configuration mechanism: http://docs.grails.org/latest/guide/testing.html#integrationTesting
As a third option, you could also use functional testing to verify that in the end everything appears to function as it is supposed to: http://docs.grails.org/latest/guide/testing.html#functionalTesting
How to bind #Value annotated fields of service in unit tests?
One way to do it...
#TestFor(MyService)
class MyServiceSpec extends Specification {
#Unroll
void "test get some url for #lang"() {
when:
service.urlTemplate = 'some value'
def someUrl = service.getSomeUrl(lang)
then:
someUrl.endsWith(lang + '.html')
where:
lang << ['es', 'en']
}
}
In case this helps someone.
I had an issue where a missing property variable used in a #Value was giving me an BeanExpressionException for a service unit test. I found that setting that variable in my application.yml for the test environment solved my problem in Grails 4.
#Value in question:
#Value("#{\${some_property_here}}") public Map<String, Map<String, Integer>> SOME_MAP_OF_MAPS
Here's a unit test that works fine.
#Subject([WeatherServiceImpl.class,URLConnection.class])
class WeatherServiceImplSpec extends Specification{
def "First spock test I ever wrote"(){
given: "some mock objects"
//1. define mock HttpURLConnection object
def mockConnObj=Mock(HttpURLConnection.class)
//2. defn of another mock
def mockURLAdaptor=Mock(URLAdapter)
when: "define some calls"
def test=new WeatherServiceImpl(mockURLAdaptor)
test.run("Raleigh")
then: "make some assertions"
1*mockURLAdaptor.openConnection(_)>>mockConnObj
1*mockConnObj.getResponseCode()
}//end def test
}
What I don't understand is that if I do this in the 'given' block:
def mockURLAdaptor = Mock(URLAdapter) >> {
openConnection(_) >> mockConnObj
}
then the method stub doesn't actually return the mock connection object as intended. To me, this is the more natural flow of expressions. Doing the same thing in the 'then' block, however, works as intended. Not sure what's going on here. Can't seem to find a relevant discussion on the web. I may also post this on stackoverflow.
Here's the class under test:
package com.icidigital.services.impl
import com.icidigital.Helpers.URLAdapter
import com.icidigital.services.IWeatherService
public class WeatherServiceImpl implements IWeatherService {
private URLAdapter urlAdapter;
private URLConnection urlConn;
public WeatherServiceImpl(URLAdapter urlAdapter){
//injecting this dependency, so I can unit test
//by injecting a mock URLAdapter instance. In
//normal operation, urlAdaptee would be an instance
//of URLWrapper, which simply wraps around the
// URL class, which is a final class and cannot
// be mocked normally.
this.urlAdapter=urlAdapter;
}
public String run(String city){
...
..
urlConn=urlAdapter.openConnection(city);
//(throws a null pointer exception while spock-ing)
urlConn.setRequestMethod("GET");
}
}
And here's the url adapter that exposes the method: openConnection. In the running code, there is a class URLWrapper that simply wraps around the java.net.URL class. I needed to do this to get around the fact that I couldn't directly mock the java.net.URL class since it is a final class.
interface URLAdapter {
public HttpURLConnection openConnection(String cityName);
}
If you want to return some object you should use a Stub instead.
#Subject([WeatherServiceImpl.class,URLConnection.class])
class WeatherServiceImplSpec extends Specification{
def "First spock test I ever wrote"(){
given: "some mock objects"
//1. define mock HttpURLConnection object
def mockConnObj=Mock(HttpURLConnection.class)
//2. defn of another mock
def mockURLAdaptor=Stub(URLAdapter)
mockURLAdaptor.openConnection(_)>>mockConnObj
when: "define some calls"
def test=new WeatherServiceImpl(mockURLAdaptor)
test.run("Raleigh")
then: "make some assertions"
1*mockConnObj.getResponseCode()
}//end def test
}
You can do it with Mocks as well, I just tried this and it worked
def "First spock test I ever wrote"() {
given: "some mock objects"
//1. define mock HttpURLConnection object
def mockConnObj = Mock(HttpURLConnection.class)
//2. defn of another mock
def mockURLAdaptor = Mock(URLAdapter)
1 * mockURLAdaptor.openConnection(_) >> mockConnObj
when: "define some calls"
def test = new WeatherServiceImpl(mockURLAdaptor)
test.run("Raleigh")
then: "make some assertions"
1 * mockConnObj.getResponseCode()
}//end def test
Hope it helps!
The following work(s):
#Subject([WeatherServiceImpl.class,URLConnection.class])
class WeatherServiceImplSpec extends Specification{
def "First spock test I ever wrote"(){
given: "some mock objects"
//1. define mock HttpURLConnection object
def mockConnObj=Mock(HttpURLConnection.class)
//=========================================
//2. defn of another mock
// Either/Or:
//def mockURLAdaptor=Mock(URLAdapter)
def mockURLAdaptor=Stub(URLAdapter)
//followed by:
mockURLAdaptor.openConnection(_)>>mockConnObj
//OR
def mockURLAdaptor=Stub(URLAdapter){
openConnection(_)>>mockConn
}
//BUT NOT:
def mockURLAdaptor=Mock(URLAdapter){
openConnection(_)>>mockConn
}
//=========================================
when: "define some calls"
def test=new WeatherServiceImpl(mockURLAdaptor)
test.run("Raleigh")
then: "make some assertions"
1*mockConnObj.getResponseCode()
}//end def test
}
Update: I found the problem. I needed to save the "train" domain as follows.
train.save(flush: true)
I needed to provide a flush, as well.
I edited to include the information requested. Thanks.
I have two domain classes as follows.
class Train {
String name
static hasMany = [passengers: Person]
. . .
}
class Person {
String firstName
String lastName
. . .
}
I am trying to use a where query to look for passengers with a given first name. Here is the full integration test code. The first query, looking for the passenger, does not work. The second one, looking for the train by name, works.
I am using Grails 2.2.1 and am running the test inside of my IDE, Groovy/Grails Tool Suite 3.2. I am not bootstrapping data, but am adding data in the test. Please see the testSomething code below.
Here is the test code.
import grails.converters.*
import static org.junit.Assert.*
import org.junit.*
class TrainIntegrationTests {
#Before
void setUp() {
// Setup logic here
}
#After
void tearDown() {
// Tear down logic here
}
#Test
void testSomething() {
def person1 = new Person()
person1.firstName = "George"
person1.lastName = "Romero"
person1.save();
println "person1.id: " + person1.id
def person2 = new Person()
person2.firstName = "Jane"
person2.lastName = "Smith"
person2.save();
def train = new Train()
train.name = "This Train"
train.addToPassengers(person1)
train.addToPassengers(person2)
train.save()
// This prints out 2.
println "passengers size" + train.passengers.size()
// This does not work. No results are returned.
def query = Train.where {
passengers {
firstName == 'George'
}
}
def qResults = query.list()
// No results
println "qResults: " + qResults
// This does work. Results returned.
def query1 = Train.where {
name == 'This Train'
}
def qResults1 = query1.list()
// Returns results.
println "qResults1: " + qResults1
// Don't really care about assert results yet.
// Just looking at the print outs and seeing how this all works.
assert true
}
}
What am I missing in the passengers query?
All,
I found the problem. I needed to save with a flush, as well.
Instead of . . .
train.save()
I used . . .
train.save(flush: true)
The query began working after that.