I have a GroovyMock of a static method. When my mock method is called the test fails because the correct arguments were not used, even though I accept all arguments to the mock. Why is this please?
// FileDownloadingService.groovy
class FileDownloadingService {
// I am going to mock this static method
static void download(URL urlLocation, String localDir, String localName) {
}
}
// ServiceUnderTestService.groovy
class ServiceUnderTestService {
def downloadData(URL url) {
FileDownloadingService.download(url, "temp", "ReferenceData.gz")
}
}
// within ServiceUnderTestServiceSpec
void "file is downloaded"() {
given: "A url for the file to download"
def urlLocation = "http://example.com/ReferenceData.gz"
def url = new URL(urlLocation)
def fileDownloadMock = GroovyMock(FileDownloadingService, global: true)
when: "we call downloadData"
service.downloadData(url)
then: "we actually try to download it"
1 * fileDownloadMock.download(_, _, _)
}
I get the following error message:
| Too few invocations for:
1 * fileDownloadMock.download(_, _, _) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * fileDownloadMock.download(http://example.com/ReferenceData.gz, 'temp', 'ReferenceData.gz')
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
Why does the mock not pass, as I'm specifying all parameters are valid, no?
For a static method, the interaction needs to be specified as follows:
1 * FileDownloadingService.download(*_) // or: (_, _, _)
Related
I am writing a Jenkins pipeline library, and am having some difficulties with mocking/validating an existing Jenkins pipeline step.
I am using jenkins-spock by homeaway to unit test, but I think my problem is more Spock related.
import com.homeaway.devtools.jenkins.testing.JenkinsPipelineSpecification
import com.company.pipeline.providers.BuildLogProvider
class PublishBuildLogSpec extends JenkinsPipelineSpecification {
BuildLogProvider buildLogProvider = Mock()
PublishBuildLog publishBuildLog
def setup () {
publishBuildLog = new PublishBuildLog(buildLogProvider: buildLogProvider)
explicitlyMockPipelineStep('writeFile')
}
def "Gets the log file contents for a specific job and build"() {
when:
"the call method is executed with the jobName and buildNumber parameters set"
publishBuildLog.call("JOBNAME", "42")
then:
"the getBuildLog on the buildLogProvider is called with those parameters"
1 * buildLogProvider.getBuildLog("JOBNAME", "42")
}
def "the contents of log file is written to the workspace"() {
given:
"getBuildLog returns specific contents"
def logFileText = "Example Log File Text"
buildLogProvider.getBuildLog(_, _) >> logFileText
when:
"publishBuildLog.call is executed"
publishBuildLog.call(_, _)
then:
"the specific contents is passed to the writeFile step"
1 * getPipelineMock("writeFile").call([file: _ , text: logFileText])
}
}
This is my unit test. I am attempting to say that writeFile is called with the text matching the contents of logFileText, ignoring what the other parameters are. I have tried numerous combinations, but always seem to get the same or similar response to response of:
Too few invocations for:
1 * getPipelineMock("writeFile").call([file: _ , text: "Example Log File Text"]) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * (explicit) getPipelineMock("writeFile").call(['file':'filename', 'text':'Example Log File Text'])
This is to test this class
import com.company.pipeline.providers.BuildLogProvider
class PublishBuildLog {
BuildLogProvider buildLogProvider = new BuildLogProvider()
void setBuildLogProvider(BuildLogProvider buildLogProvider) {
this.buildLogProvider = buildLogProvider
}
def call(def jobName, def buildNumber) {
def contents = buildLogProvider.getBuildLog(jobName, buildNumber)
writeFile(file: "filename", text: contents)
}
}
I am at a loss as to how to validate this call. I have a lot of experience with Java and Junit, but I am relatively new to Spock.
How can I verify this?
For me your test passes. But there is one thing I find strange: You use jokers in a when: block where you should really use concrete parameters like in the first feature method:
when: "publishBuildLog.call is executed"
publishBuildLog.call(_, _)
Instead you should write:
when: "publishBuildLog.call is executed"
publishBuildLog.call("JOBNAME", "42")
For me this works just fine if I use this as a dummy class in order to make the code compile (because you did not provide the source code):
class BuildLogProvider {
def getBuildLog(def jobName, def buildNumber) {}
}
I am writing Junit testcases for a Grails project.
Here I am using Spock framework to write testcases.
Here I am trying to test following method.
But I want to mock/stub the rest.post method. I don't want call the actual url passed.
def RestResponse restPost(String url, Map headerMap, Map jsonDataMap) {
RestBuilder rest = new RestBuilder()
RestResponse response = rest.post(url) {
headerMap.each { k, v -> header(k, v) }
header('contentType', 'application/json')
header('Accept-API-Version', 'resource=2.0,protocol=1.0')
if (jsonDataMap)
json(jsonDataMap)
}
response
}
I tried with MockFor. It is calling actual url.
void "test restPost"() {
setup:
RestResponse resMock = new RestResponse()
def httpBuildMock = new MockFor(RestBuilder)
httpBuildMock.demand.post(_) >> resMock
when:
def url = "http://testme"
def headerMap = [
'Authorization': 'Basic ' + 'encodedStr'
]
def dataMap = [
'operation': 'replace',
'field' : 'userPassword',
'value' : 'devicePassword'
]
RestResponse res = service.restPost(url, headerMap, dataMap)
then:
res
}
So how to mock/stub a particular method of class?
You could create a seperate method to create the RestBuilder so createRestBuilder and then return a mock everytime this method is called:
def RestResponse restPost(String url, Map headerMap, Map jsonDataMap) {
RestBuilder rest = createRestBuilder()
RestResponse response = rest.post(url) {
headerMap.each { k, v -> header(k, v) }
header('contentType', 'application/json')
header('Accept-API-Version', 'resource=2.0,protocol=1.0')
if (jsonDataMap)
json(jsonDataMap)
}
response
}
then define service with
def service = Spy(ServiceClass) {
// stub a call on the same object
createRestBuilder() >> Mock(RestBuilder)
}
I am attempting to write a test for a controller which calls a service method. I would like to mock a dependent method within that service.
My spec is as follows:
MyController myController = new MyController()
def mockMyService
def "My spy should be called"() {
when:
mockMyService = Spy(MyService) {
methodToSpy() >> {
println "methodToSpy called"
} // stub out content of this fn
}
myController.myService = mockMyService
myController.callService()
then:
1 * mockMyService.methodToSpy()
}
When I attempt to run this test, I get the following error:
Failure: |
My spy should be called(spybug.MyControllerSpec)
|
Too few invocations for:
1 * mockMyService.methodToSpy() (0 invocations)
Unmatched invocations (ordered by similarity):
1 * mockMyService.serviceMethod()
1 * mockMyService.invokeMethod('methodToSpy', [])
1 * mockMyService.invokeMethod('println', ['in serviceMethod about to call methodToSpy'])
1 * mockMyService.invokeMethod('println', ['Back from methodToSpy'])
As you can see, Spock is capturing the Groovy invokeMethod call, not the subsequent call to the actual method. Why is this happening?
The complete project is available here.
Try this:
def "My spy should be called"() {
given:
mockMyService = Mock(MyService)
myController.myService = mockMyService
when:
myController.callService()
then:
1 * mockMyService.methodToSpy(_) >> { println "methodToSpy called" }
}
According to the spock documentation for stubs, if you want to use the cardinality, you must use a Mock and not a Stub.
http://spockframework.github.io/spock/docs/1.0/interaction_based_testing.html#_stubbing
I am in grails 2.3.1 - trying to use the async features.
This is bulk data processing. I am trying to synchronise 2 databases, which involves comparing both and returning a list of 'deltas'. I am trying to speed up the process
The documentation says I can just add a set of closures to a PromiseList and then call onComplete() to check that all the closures have completed. These are my attempts - directly building on "You can also construct a PromiseList manually" in the documentation:
def tasksMemberDeltas = new PromiseList()
pages.each {Integer page ->
tasksMemberDeltas << {findCreateMemberDeltas(page, (page + pageSize) - 1)}
if (page % 30 == 0) {
tasksMemberDeltas.onComplete {
tasksMemberDeltas = new PromiseList()
}
}
Returns:
Error groovy.lang.MissingMethodException:
No signature of method: java.util.ArrayList.onComplete()
In the end I called .get() which calls waitAll. Going into .get() and finding that it did waitAll was my revelation.
So if I have a single task I call:
waitAll finalDeltas
If I have a list I call:
taskFinalDeltas.get()
onComplete() logically relates to a single delta. Not the list. So this works OK:
Promise memberDeleteDeltas = task {
findDeleteAndTagDeltas()
}
memberDeleteDeltas.onError { Throwable err ->
println "An error occured ${err.message}"
}
memberDeleteDeltas.onComplete { result ->
println "Completed create deltas"
}
waitAll(memberDeleteDeltas)
Below is my Geb Page, Spec and Error. I am not sure where and what the issue is. When I remove the below from the ApplicationSummaryPage then I doesn't get this error.
ds(wait: true)
{ module DatasourceInformationRow, $("table.ic-table-creditReportProduct table tr", it) }
class ApplicationSummaryPage extends Page
{
static url = "application-summary/application-summary.jsf"
static at =
{ assert title == "Application Summary" }
static content =
{
menu
{ module MenuModule }
userPanel
{module UserPanelModule }
ds(wait: true)
{ module DatasourceInformationRow, $("table.ic-table-creditReportProduct table tr", it) }
applicationSummaryForm
{ $("#applicationSummary_form") }
workItemDiv
{$("div", id: "consumerWorkItems:workItemPanel")}
workItemsSection
{workItemDiv.find (".ui-panel-title").text()}
resubmitLink
{$("a",id: "loginForm")}
overrideDecisionLink
{$("a",id: "loginForm")}
addNoteLink
{$("a",id: "loginForm")}
}
}
Spec
class SearchSpec extends BaseUiSpec
{
def setup()
{
login("manager")
}
def "cccc"()
{
when: "I search"
to SearchPage
at SearchPage
applicationid.value "10002000000010000"
searchButton.click()
at SearchPage
waitFor
{ searchResultsData }
println "------------"+ searchResults(0).ApplicationId.text()
searchResults(0).ApplicationId.click(ApplicationSummaryPage)
Thread.sleep 5000
at ApplicationSummaryPage
println "-----???"+ ds
}
}
Error
geb.waiting.WaitTimeoutException: condition did not pass in 15.0 seconds (failed with exception)
at geb.waiting.Wait.waitFor(Wait.groovy:126)
at geb.content.PageContentTemplate.create(PageContentTemplate.groovy:117)
at geb.content.PageContentTemplate.get(PageContentTemplate.groovy:98)
at geb.content.NavigableSupport.getContent(NavigableSupport.groovy:43)
at geb.content.NavigableSupport.propertyMissing(NavigableSupport.groovy:127)
at geb.Browser.propertyMissing(Browser.groovy:175)
at geb.spock.GebSpec.propertyMissing(GebSpec.groovy:55)
at test.SearchSpec.cccc(SearchSpec.groovy:33)
Caused by: geb.error.InvalidPageContent: Definition of page component template '$' of 'ApplicationSummaryPage' is invalid, params must be either a Closure, or Map and Closure (args were: [class java.lang.String, null])
at geb.content.PageContentTemplateBuilder.throwBadInvocationError(PageContentTemplateBuilder.groovy:69)
at geb.content.PageContentTemplateBuilder.methodMissing(PageContentTemplateBuilder.groovy:51)
at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java:44)
at com.equifax.ic.testing.framework.ui.pages.applicationmanagement.ApplicationSummaryPage._clinit__closure2_closure5(ApplicationSummaryPage.groovy:24)
at com.equifax.ic.testing.framework.ui.pages.applicationmanagement.ApplicationSummaryPage._clinit__closure2_closure5(ApplicationSummaryPage.groovy)
at geb.content.PageContentTemplate.invokeFactory(PageContentTemplate.groovy:134)
at geb.content.PageContentTemplate.create_closure1(PageContentTemplate.groovy:103)
at geb.content.PageContentTemplate.create_closure1(PageContentTemplate.groovy)
at geb.waiting.Wait.waitFor(Wait.groovy:115)
... 7 more
The problem was that i wan't passing the index for ds. The corrected version is below
println "-----???"+ ds(0)
Got the response on Geb mailing list. Posting here for others.