What I'm trying to do is create a method mock that returns a mock so I can test the folloging disconnectNode method of a class. What I'm trying to mock is the getNode and toComputer calls in the getJenkinsNode method.
Computer getJenkinsNode(String nodeName) {
return Jenkins.getInstanceOrNull().getNode(nodeName).toComputer()
}
def disconnectNode(String nodeName) {
def offlineCause = 'Maintenance'
def node = getNode(nodeName)
node.setTemporarilyOffline(true, new OfflineCause.ByCLI(offlineCause))
}
But, I'm not there yet. I'm trying the figure out why I can't make a mock return another mock.
With jenkins-spock and Spock I managed to do the following test specification just for trying to locate the problem
import com.homeaway.devtools.jenkins.testing.JenkinsPipelineSpecification
import hudson.model.Computer
import hudson.model.Node
import jenkins.model.Jenkins
class MaintenanceSpec extends JenkinsPipelineSpecification {
def 'Script does not fail or throw exceptions'() {
given:
Computer computer = Mock()
Node node = Mock()
node.toComputer() >> computer
Jenkins jenkins = getPipelineMock('Jenkins')
jenkins.getNode('Node 1') >> node
when:
System.out.println(jenkins.getNode('Node 1').toString())
System.out.println(computer.toString())
System.out.println(jenkins.getNode('Node 1').toComputer().toString())
System.out.println(node.toComputer().toString())
then:
noExceptionThrown()
}
}
The printed messages after the test are.
Mock for type 'Node' named 'node'
Mock for type 'Computer' named 'computer'
null
null
The result is really confusing. With the first print I can tell that the getNode function is returning the mocked Node as expected. With the second print I can tell that the mock for the Computer class is created. But the 3rd and 4th prints are returning null so the problem is with the mock for the method toComputer but I don't know what I'm doing wrong
Any ideas?
Thank you!
Related
I have grails 2.4.4 and Cobertura as covert test.
I have code like:
lstPerspectives = Perspectives.findAllByDbAndSysDelete(dbInstance, new Long(0))
But Cobertura don´t pass the test because don´t search in my DB, How can I pass this line?, How can overwrite this value? I send this lstPerspectives but it don´t take it.
Thanks
Thanks
Try something like the following:
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
#TestFor(Perspectives)
#Mock([Perspectives])
class PerspectivesSpec
{
void "test Perspectives"(){
given:
def dbInstance = 'aDbInstance' // don't know what this is
def sysDelete = false // is this a boolean?
new Perspectives( dbInstance: dbInstance, sysDelete: sysDelete ).save( failOnError: true )
when:
// run you bit of code that executes the snippet in your question
then:
// check your desired outcome
}
}
I don't know if you are testing your Perspectives class directly here or something else, controller, service? so had to make a few assumptions.
In my Test, I have some feature methods that only need to run in certain situations. My code looks something like this:
class MyTest extends GebReportingSpec{
def "Feature method 1"(){
when:
blah()
then:
doSomeStuff()
}
def "Feature method 2"(){
if(someCondition){
when:
blah()
then:
doSomeMoreStuff()
}
}
def "Feature method 3"(){
when:
blah()
then:
doTheFinalStuff()
}
}
I should note I am using a custom spock extension that allows me to run all feature methods of a spec even if a previous feature method fails.
The thing I just realized and the reason I am making this post, is because "Feature method 2" does not show up in my test results for some reason, but method 1 and 3 do. Even if someCondition is set to true, it does not appear in the build results. so I am wondering why this is, and how I can make this feature method conditional
Spock has special support for conditionally executing features, take a look at #IgnoreIf and #Requires.
#IgnoreIf({ os.windows })
def "I'll run everywhere but on Windows"() { ... }
You can also use static methods in the condition closure, they need to use the qualified version.
class MyTest extends GebReportingSpec {
#Requires({ MyTest.myCondition() })
def "I'll only run if myCondition() returns true"() { ... }
static boolean myCondition() { true }
}
Your test is not appearing in the report as you cant have the given, when, then blocks inside of a conditional.
You should always run the test but allow the test to fail gracefully:
Use the #FailsWith attribute. http://spockframework.org/spock/javadoc/1.0/spock/lang/FailsWith.html
#FailsWith(value = SpockAssertionError, reason = "Feature is not enabled")
def "Feature method 2"(){
when:
blah()
then:
doSomeMoreStuff()
}
Important to note that this test will be reported as passed when it fails with the specified exception. And it will also reported as passed if the feature is enabled and the test actually passed.
To Fix this I simply put a when/then block with a 10 ms sleep before the if statement and now that feature method is being executed
I've a strange polluting situation between two spock integration tests that I'm not able to resolve. I suppose that I'm doing something wrong but I can't understand what.
The two integration tests are testing different situation of the same controller. In the first one I mock a service while in the second I don't mock.
Here are the significant parts of two tests :
test 1:
// CodeControllerSpec.groovy
...
def controller = new CodeController()
def serviceMock = new MockFor(PollutingService)
serviceMock.demand.search(1) { a, b, c ->
return [id: 1]
}
controller.myService.pollutingService = serviceMock.proxyInstance()
controller.save()
...
then:
serviceMock.verify(controller.myService.pollutingService)
test 2:
// CodeEngineSpec.groovy
...
def controller = new CodeController()
controller.show()
...
then:
...
Controller and services are as following
// CodeController
class CodeController extends RestfulController<Code> {
def myService
def show() {
...
myService.execute()
...
}
}
// MyService
class MyService {
def pollutingService
def execute() {
...
pollutingService.search(a, b, c)
...
}
}
// PollutingService
class PollutingService {
def search(a, b, c) {
...
...
}
}
If I run the two tests one by one, they all pass but, if I run them together, the second one fails with
No more calls to 'search' expected at this point. End of demands.
I'm sure that the mock in the first service is used (I've debugged code line by line) but I don't know why mock is not cleaned after test.
Any suggestion is really welcome.
I'm using grails 2.3.8
First of all, using mocks in integration tests has unpredictable results.
But putting that aside, where is controller.myService in your first test being instantiated? I would have expected that calling controller = new CodeController() would bypass autowiring of controller.myService.
I'm having an issue performing an integration test in Grails 2.4.5.
The service I want to test looks like this:
class MyService {
def myBean
def serviceMethod() {
myBean.beanMethod()
}
}
where myBean is defined in resources.groovy:
beans = {
myBean(MyBeanImpl)
}
And here comes the integration test:
MyServiceIntegrationSpec extends IntegrationSpec {
def myService
def setup() {
def myBeanMock = Mock(MyBeanImpl)
myBeanMock.beanMethod(_) >> 'foo'
myService.myBean = myBeanMock
}
void "silly test"() {
expect:
myService.serviceMethod() == 'foo'
}
}
Well, this badly fails since myService.serviceMethod() returns null.
I've already tried
ReflectionTestUtils.setField(myService, 'myBean', myBeanMock)
instead of
myService.myBean = myBeanMock
with no luck.
Of course this simplified example could be handled with a unit test, but the real case I'm facing needs an integration test since data persistence is involved.
myBeanMock.beanMethod(_) >> 'foo' expects one parameter.
You can either use
myBeanMock.beanMethod() >> 'foo'
or
myBeanMock.beanMethod(*_) >> 'foo'.
Either case mocking should not be part of Integration spec because this is an integration test. In your case as explained, there might be a need.
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.