Cannot perform unit test with function which have createCriteria() statement - groovy

I want to write a unit test (by JUnit) to test value of this function in Groovy:
String getPeopleNamesById(int[] peopleIds) {
List<String> names = People.createCriteria().list{
projections { property("name") }
'in' ("id", peopleIds)
}
return names ? names.join(", ") : "";
}
But the unit test always fails when reading this statement: List names = People.createCriteria().list{...}
groovy.lang.MissingMethodException: No signature of method: People.createCriteria() is applicable for argument types: () values: [].
I guess it because of calling to functions which execute some DB connections and queries?
Could you please help me write this test? Thank you so much!

Criteria queries aren't available in unit tests, and aren't provided by mockDomain. You can either mock your criteria queries yourself, e.g. with mockFor, or make your test an integration test, where you have access to a full database environment.
Here's an example of how you could mock your query:
mockFor(People).demand.static.createCriteria = { ->
[list: { closure -> [ <some mock objects> ] } ]
}

Related

test void simple method with spock

I have the following method need to be tested:
class Person {
String getFileName(String number) {
return "file"+number
}
void updateSpec(String number) {
new File(getFileName(number)).delete()
}
}
I try to create the testcase like this:
def "update spec"() {
given:
Person person = new Person()
when:
person.updateSpec('1')
then:
1 * File.delete()
}
it says:
Too few invocations for:
1 * File.delete() (0 invocations)
what is the problem and how to fix it, thanks!
And is there a good way to test this method?
Depends on what do you want to test. At first you have to use Mock or Spy to be able to test invocation count.
For example you can test if getFileName() method was called from updateSpec() method and if it was called with '1' argument like this:
def "update spec"() {
given:
Person person = Spy(Person)
when:
person.updateSpec('1')
then:
1 * person.getFileName('1')
}
If you really need to test whether the File.delete() was called, then it will be better to change Person class little bit, because you need File mock on which you can check the invocation count:
class Person {
File getFile(String number) {
return new File("file" + number)
}
void updateSpec(String number) {
getFile(number).delete()
}
}
And the test can be then:
def "File delete was called"() {
given:
File file = Mock(File)
Person person = Spy(Person)
person.getFile(_) >> file
when:
person.updateSpec('1')
then:
1 * file.delete()
}
Another option will be to inject some FileService, wich will encapsulate the File.delete() method, into the Person class and test invoication on it.
You can only define interactions between the object under specification and its mocked dependencies. In your example, however, you are "specifying" an interaction with File class, not mock object. See Spock's Interaction Based Testing. Technically, you can achieve/change your goal as suggested in #cgrim answer. Or you can use tools such as PowerMock (w/o Spock) to mock almost everything but REMEMBER, this kind of technique should only be taken as a last resort. Basically, if you adhere to best design practices then you will never need such tools. Unless you have to deal with some legacy code

How can I use Arrow-kt's Some() in Groovy code?

I'm trying to test my Kotlin code, which has Arrow-kt types, using Spock in Groovy. However, I'm not able to use Arrow-kt's additions such as Some. For example, I have a test as follows:
#Unroll
def "add returns #expected for queryRecord #queryRecord"() {
given:
def ip = "ip"
def rule = "rule"
when:
def result = unit.add(ip, rule)
then:
1 * dynamoDBMapperMock.load(ActionRecord.class, ip) >> queryRecord
result == expected
where:
queryRecord | expected
new ActionRecord() | None.INSTANCE
null | Some(new ActionInternal("ip"))
}
While the first data row succeeds with no problems, the second one fails with the following error:
groovy.lang.MissingMethodException: No signature of method: package.name.EventSpec.Some() is applicable for argument types: (package.name.ActionInternal) values: [ActionInternal(dropletIp=null)]
Possible solutions: Mock(), Spy(), Stub(), dump(), Mock(groovy.lang.Closure), Mock(java.lang.Class)
I've tried .some() as well, but not to avail. Apparently Groovy can't access Kotlin extensions, but Some is simply a data class[1], so I'm not sure why I cannot use it in Groovy.
Yes, you can use Arrow Datatypes in Groovy, the result is not as idiomatic as in Kotlin because the library heavily depends on extension functions and functions in the companion object
Example
import arrow.core.Option
import static arrow.core.OptionKt.getOrElse
static main(args){
println 'What is your name?'
def name = Option.#Companion.fromNullable(System.in.newReader().readLine())
.filterNot { it.isEmpty() }
.map { it.toUpperCase() }
println("Welcome ${getOrElse(name) { 'Anonymous' }}")
}
Output
'Welcome JOHN' (or 'Welcome Anonymous' if the provided name is null or empty)
As you can see, to be able to use getOrElse extension function, we need to import it as a static method
Hint
Do not use Some directly unless you are absolutely sure the value is not null, otherwise, you should rely on Option.fromNullable to safely lift the value to the Option context (i.e create Some or None depending if the value is null or not)

Stubbed method should return value depending on given mock parameter in Spock

I would like to have different returning results - depending on the given mocked parameter of a method. Please consider the following code snippet to follow my intention
class ExampleSpec extends Specification {
def "should return second value of list of return values"() {
given:
Person personBob = Mock()
Person personJackson = Mock()
PersonHelper stubbedPerson = Stub()
stubbedPerson.getNameOfBrother(personBob) >> "Billy Bob";
stubbedPerson.getNameOfBrother(personJackson) >> "Tommy Jackson";
when:
String actual = stubbedPerson.getNameOfBrother(personBob)
String actual2 = stubbedPerson.getNameOfBrother(personJackson)
then:
actual == "Billy Bob" // true
actual2 == "Tommy Jackson" // false "Billy Bob"
}
}
The test fails because the second call for var actual2 still return Billy Bob rather than Tommy Jackson. I know there is a way to return different values by call order but I would like to make it dependend on given mocks.
Using normal values - no Mock/Stub Proxies - as parameter values does actually work. I assume that the Spock engine can not differ between two mocks. But I am unsure about this, because the proxies do have IDs as instance fields.
For the record - stubbing with mock objects works. I've added simple Person and PersonHelper classes to your example and the test passes:
import spock.lang.Specification
class ExampleSpec extends Specification {
def "should return second value of list of return values"() {
given:
Person personBob = Mock()
Person personJackson = Mock()
PersonHelper stubbedPerson = Stub()
stubbedPerson.getNameOfBrother(personBob) >> "Billy Bob";
stubbedPerson.getNameOfBrother(personJackson) >> "Tommy Jackson";
when:
String actual = stubbedPerson.getNameOfBrother(personBob)
String actual2 = stubbedPerson.getNameOfBrother(personJackson)
then:
actual == "Billy Bob" // true
actual2 == "Tommy Jackson" // false "Billy Bob"
}
static class Person {
String name
}
static class PersonHelper {
String getNameOfBrother(Person person) {
return null
}
}
}
I have checked it with spock-core:1.1-groovy-2.4, spock-core:1.0-groovy-2.4 and even spock-core:0.7-groovy-2.0. All worked.
But what is even more important - such test does not make any sense. You don't test your code at all. You only test if mocking framework mocks correctly. This test could make some sense if you use Spock mocks in your production code, but this is not a valid assumption.
What may go wrong?
Think for a second about this test. According to your when: block you are trying to test if PersonHelper.getNameOfBrother(Person person) returns a valid name of a brother for two different objects. Now let's assume that this is the only test of a PersonHelper class in your project. Imagine what happens if suddenly implementation of getNameOfBrother method starts throwing NullPointerException for some random reason. Ask yourself - does your unit test protects you from such situation? Nope. Your test always passes, because you are stubbing the method you are testing. If you test a real implementation instead and you pass a real Person object then you will get notified about NullPointerException in the test. Otherwise you will see it when you deploy your code and some user's action calls this method and it fails.

Mockito mock creation inside mock creation

The error I get is org.mockito.exceptions.misusing.UnfinishedStubbingException, with one of the possible reasons "you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed".
val mockHttpHandlerContext = mock<HttpHandlerContext>().let {
whenever(it.request).thenReturn(mock<HttpRequest>().let {
whenever(it.queryParameters).thenReturn(mapOf(
"itype" to listOf("msisdn"),
"uid" to listOf(inputMsisdn)
))
it
})
whenever(it.scope()).thenReturn(ProcessingScope.of(Timings("test", 1000L)))
it
}
Is the only solution to get rid of nested mock creation? It would really make code harder to understand, maybe there is a known workaround?
The code snippet is Kotlin.
Judging by the naming, I assume you're using nhaarman/Mockito-Kotlin?
Mockito is stateful, you must create mocks sequentially, but there are some ways of flipping the order of evaluation. For example,
val mockHttpHandlerContext2 = mock<HttpHandlerContext>() {
mock<HttpRequest>() {
on { queryParameters }.thenReturn(mapOf(
"itype" to listOf("msisdn"),
"uid" to listOf(inputMsisdn)
))
}.let { on { request }.thenReturn(it) }
on { scope() }.thenReturn(ProcessingScope.of(Timings("test", 1000L)))
}
I'm taking advantage of the mock() overload with a KStubbing<T> receiver, but the important bit is creating the inner mock first before using .let to set it on the stub.
Another option would be to use .thenAnswer to defer creation of the inner mock until the time when stubbed method is called.
val mockHttpHandlerContext = mock<HttpHandlerContext>() {
on { request }.thenAnswer {
mock<HttpRequest>() {
on { queryParameters }.thenReturn(mapOf(
"itype" to listOf("msisdn"),
"uid" to listOf(inputMsisdn)
))
}
}
on { scope() }.thenReturn((ProcessingScope.of(Timings("test", 1000L)))
}
Note that this will create a new mock every time the stubbed method is called. It might not be desirable in some situations, such as if you want to perform verification on the inner mock.

Creating spock tests in runtime

Is there any possibility to create spock tests in runtime? I tried to create several meta-methods in a loop within a GebSpec but they are ignored during the tests execution.
Or maybe somebody could suggest any workarounds?
Thanks in advance!
As #Tim mentioned, datatables are the way to go.
You don't need to duplicate code in data tables, you can make them fully dynamic.
#Unroll
def "Check form submit params: '#login', '#pwd'. Expected - #result"(String login, String pwd, boolean result) {
setup:
// do your test
where: [login, pwd, result] << [ [ "user", "qwerty", true], [ "user", "1234", false] ]
}
Please note nested arrays in where clause. It can actually be a fully dynamic array created at runtime.
Also please notice an #Unroll annotation, as it will give you nice test method names.
you can simple write loop/sql query in where clause. a test suite runs accordingly to the number of where possible.
example:
#Unroll
def "test suite for each student"(){
given: ""
.......................
and : ""
.......................
then: ""
........................
where: ""
for (StudentList student : list){
//operations
//load the values in the variables such as there numbers or ids
}
}
if the loop is true for 10 students, the suite will be executed 10 times

Resources