Refactoring mocking code into another class causes Spock tests to fail - unit-testing

I have a Groovy/Spock unit test as follows:
public class ThingUnitTest extends Specification {
def "doing a thing delegates to the context"() {
given : def thing = createThing()
when : thing.doThing()
then : 1 * thing.context.doThing()
}
def createThing() {
def thing = new ThingImpl()
thing.context = createThingContext()
return thing
}
def createThingContext() {
def context = Spy(ThingContext)
context.foo = Mock(Foo)
context.bar = Mock(Bar)
return context
}
}
This test will run without problems. However it turns out that I have other tests that need a ThingContext, so I want to move the createThingContext code into a common class:
public class ThingContextFactory extends Specification {
def createThingContext() {
def context = Spy(ThingContext)
context.foo = Mock(Foo)
context.bar = Mock(Bar)
return context
}
}
and then write my unit tests as follows:
public class ThingUnitTest extends Specification {
...
def createThingContext() {
return new ThingContextFactory().createThingContext()
}
}
But now the test fails, with the assertion 1 * thing.context.doThing() failing with zero interactions.
I also tried the following:
public class ThingContextFactory {
def createThingContext() {
def mocking = new MockingApi()
def context = mocking.Spy(ThingContext)
context.foo = mocking.Mock(Foo)
context.bar = mocking.Mock(Bar)
return context
}
But now the tests fail with MockingApi.invalidMockCreation ... InvalidSpec
Note that I do not want to use inheritance here, but move common mocking code into helper classes. But when I do this my spock tests fail.
Is there some proper way to refactor Spock mocking code?

As of Spock 0.7, mock objects can only be created in the test class that uses them, or a superclass thereof. This might change in the next version.

Related

Mock object used insided the to be tested function using spock

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

Why Spock's Interactions doesn't work for Mock that built by other class

I'm trying to assemble all Mock building methods in one class.
but when I use Mock object that built by building method on other groovy class .
the stubbing of Mock seems work fine , but interactions check doesn't work.
well ... how should I achieve this ?
MockTestingSpec.groovy
class MockTestingSpec extends Specification{
def "use mock from other class"(){
setup:"construct mock builder"
def bldr = new MockBuilder()
when:"build mock by MockBuilder"
def mockObj = bldr.buildMock()
and:"build mock by private method of this class"
def builtAtThisClass = buildMock()
then:"check stubbing are working. these conditions were satisfied"
mockObj.getKey().equals("keyyyy")
mockObj.getValue() == 12345
builtAtThisClass.getKey().equals("keyyyy")
builtAtThisClass.getValue() == 12345
when:"put a mock to private method"
callMockGetter(builtAtThisClass)
then:"call each getter, these conditions were also satisfied"
1 * builtAtThisClass.getKey()
1 * builtAtThisClass.getValue()
when:"puta a mock that built by builder"
callMockGetter(mockObj)
then:"these conditions were NOT satisfied... why?"
1 * mockObj.getKey()
1 * mockObj.getValue()
}
// completely same method on MockBuilder.
private buildMock(String key = "keyyyy",Integer value = 12345){
TestObject obj = Mock()
obj.getKey() >> key
obj.getValue() >> value
return obj
}
private callMockGetter(TestObject obj){
obj.getKey()
obj.getValue()
}
}
MockBuilder.groovy
class MockBuilder extends Specification{
public buildMock(String key = "keyyyy",Integer value = 12345){
TestObject obj = Mock()
obj.getKey() >> key
obj.getValue() >> value
return obj
}
public static class TestObject{
private String key
public String getKey(){
return key
}
private Integer value
public Integer getValue(){
return value
}
}
}
Moving mock creation to a superclass works instead. This way you can reuse complex mock creation across multiple Specs.
abstract class MockCreatingSpec extends Specification {
createComplexMockInSuperClass() {
return Mock()
}
}
class MockTestingSpec extends MockCreatingSpec {
def "use mock from superclass"() {
given:
def mock = createComplexMockInSuperClass()
...
}
}

Mocking multiple collaborators with Groovy MockFor or StubFor

I am learning how to write unit tests with Groovy. I'm familiar with both EasyMock and Mockito but thought I'd try the pure Groovy way. The class I want to test has multiple collaborators I need to mock. The examples for MockFor demonstrate mock.use, but don't indicate how to employ more than one mock. So, I extended the Family/Person example to include a Pet and wrote a sample test for a method needing both a Person and a Pet. The only way I found to apply both a Person mock and a Pet mock was to nest mock.use closures as shown below.
This works (produces a JUnit green bar), but I'm wondering if it's the right/best way to do it? It could get ugly fast if I have to mock several collaborators in this fashion - nesting N levels deep. Ugh.
import groovy.mock.interceptor.MockFor
import org.junit.Test
class FamilyTest {
#Test
void testCuddle() {
def kidMock = new MockFor(Person)
kidMock.demand.getFirst {'Kid'}
kidMock.use {
def catMock = new MockFor(Pet)
catMock.demand.getName {'Cat'}
catMock.use {
def family = new Family(kid:new Person(), cat:new Pet())
assert family.cuddle() == 'Kid hugs Cat'
}
catMock.expect.verify()
}
kidMock.expect.verify()
}
class Person {
String first, last
}
class Pet {
String name
}
class Family {
Person kid
Pet cat
// method under test
def cuddle() { "$kid.first hugs $cat.name" }
}
}
Edit: The below works, but the verify methods don't match the documentation, which say to use mock.expect.verify(). When I try the latter, I get an exception "expected 1 call, got 0".
Again I wonder - it works, but is it the right/preferred/best way?
#Test
void testCuddle2() {
def kidMock = new MockFor(Person)
kidMock.demand.with {getFirst {'Kid'}}
def catMock = new MockFor(Pet)
catMock.demand.with {getName {'Cat'}}
def kidProxy = kidMock.proxyInstance();
def catProxy = catMock.proxyInstance();
def family = new Family(kid:kidProxy, cat:catProxy)
assert family.cuddle() == 'Kid hugs Cat'
kidMock.verify(kidProxy)
catMock.verify(catProxy)
}

running same tests for different classes in groovy and spock

I'm currently trying to run the same test cases for 2 different classes but having issues with the setup(), I see similar questions, but haven't seen the solution for groovy testing with Spock, and I haven't been able to figure it out.
So I am essentially solving the same problem using 2 different methods, so the same test cases should be applicable to both classes, I am trying to stay Don't Repeat Yourself (DRY).
So I've set up a MainTest as an abstract class and the MethodOneTest and MethodTwoTest as concrete classes that extend the abstract MainTest:
import spock.lang.Specification
abstract class MainTest extends Specification {
private def controller
def setup() {
// controller = i_dont_know..
}
def "test canary"() {
expect:
true
}
// more tests
}
My concrete classes are something like this:
class MethodOneTest extends MainTest {
def setup() {
def controller = new MethodOneTest()
}
}
class MethodTwoTest extends MainTest {
def setup() {
def controller = new MethoTwoTest()
}
}
So does anyone know how I can do run all the tests in abstract MainTest from my concrete classes MethodOneTest and MethodTwoTest? How to instantiate the setup properly? I hope I am being clear.
Just forget about controller setup. All tests from superclass will be automatically executed when you execute tests for concrete class. E.g.
import spock.lang.Specification
abstract class MainTest extends Specification {
def "test canary"() {
expect:
true
}
// more tests
}
class MethodOneTest extends MainTest {
// more tests
}
class MethodTwoTest extends MainTest {
// more tests
}
But it should have sence to run the same tests more than once. So it is resonable to parameterize them with something, e.g. some class instance:
import spock.lang.Specification
abstract class MainSpecification extends Specification {
#Shared
protected Controller controller
def "test canary"() {
expect:
// do something with controller
}
// more tests
}
class MethodOneSpec extends MainSpecification {
def setupSpec() {
controller = //... first instance
}
// more tests
}
class MethodTwoSpec extends MainSpecification {
def setupSpec() {
controller = //... second instance
}
// more tests
}

Scala and Mockito with traits

I had a simple class that naturally divided into two parts, so I refactored as
class Refactored extends PartOne with PartTwo
Then the unit tests started failing.
Below is an attempt to recreate the problem. The functionality of all three examples is the same, but the third test fails with a NullPointerException as indicated. What it is about the use of traits that is causing the problem with mockito?
Edit: Is Mockito the best choice for Scala? Am I using the wrong tools?
import org.scalatest.junit.JUnitSuite
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito.when
import org.junit.Test
import org.junit.Before
class A(val b:B)
class B(val c:Int)
class First(){
def getSomething(a:A) = a.b.c
}
class Second_A extends Second_B
class Second_B{
def getSomething(a:A) = a.b.c
}
class Third_A extends Third_B
trait Third_B{
// Will get a NullPointerException here
// since a.b will be null
def getSomething(a:A) = a.b.c
}
class Mocking extends JUnitSuite with MockitoSugar{
var mockA:A = _
#Before def setup { mockA = mock[A] }
#Test def first_PASSES {
val mockFirst = mock[First]
when(mockFirst.getSomething(mockA)).thenReturn(3)
assert(3 === mockFirst.getSomething(mockA))
}
#Test def second_PASSES {
val mockSecond = mock[Second_A]
when(mockSecond.getSomething(mockA)).thenReturn(3)
assert(3 === mockSecond.getSomething(mockA))
}
#Test def third_FAILS {
val mockThird = mock[Third_A]
//NullPointerException inside here (see above in Third_B)
when(mockThird.getSomething(mockA)).thenReturn(3)
assert(3 === mockThird.getSomething(mockA))
}
}
Seems Mockito has some kind of problem seeing the relationship between class and trait. Guess this is not that strange since traits are not native in Java. It works if you mock the trait itself directly, but this is maybe not what you want to do? With several different traits you would need one mock for each:
#Test def third_PASSES {
val mockThird = mock[Third_B]
when(mockThird.getSomething(mockA)).thenReturn(3)
assert(3 === mockThird.getSomething(mockA))
}