Mocking a singleton in Groovy - groovy

In Groovy / Spock I can mock a class by doing:
def theClass = Mock(TheClass.class)
and then wire that instance into the class under unit test. What about if I want to mock a class that has been annotated as a #Singleon

Here is a little tool class you can use:
package de.scrum_master.stackoverflow
import java.lang.reflect.Field
import java.lang.reflect.Modifier
class GroovySingletonTool<T> {
private Class<T> clazz
GroovySingletonTool(Class<T> clazz) {
this.clazz = clazz
}
void setSingleton(T instance) {
// Make 'instance' field non-final
Field field = clazz.getDeclaredField("instance")
field.modifiers &= ~Modifier.FINAL
// Only works if singleton instance was unset before
field.set(clazz.instance, instance)
}
void unsetSingleton() {
setSingleton(null)
}
void reinitialiseSingleton() {
// Unset singleton instance, otherwise subsequent constructor call will fail
unsetSingleton()
setSingleton(clazz.newInstance())
}
}
Just call setSingleton(Mock(TheClass)). For more info see this answer, I do not want to repeat the whole sample code here.
Feel free to ask follow-up questions if there is anything you do not understand.

You can use global mocks
def publisher = new Publisher()
publisher << new RealSubscriber() << new RealSubscriber()
def anySubscriber = GroovyMock(RealSubscriber, global: true)
when:
publisher.publish("message")
then:
2 * anySubscriber.receive("message")

Related

UnsupportedOperationException when using Method Pointer Operator and MockFor

I had a test. It was using mockFor and was working and I was happy. Until something changed and I was forced to use a method pointer operator, and then my happiness was a just a memory.
Here a constricted example of the problem
import groovy.mock.interceptor.*
// I am testing againts a interface, not an actual class
// this is not negociable.
interface Person {
void sayHello(name);
}
// Setup (can do whatever I need)
def personMock = new MockFor(Person)
personMock.demand.sayHello { name -> println "Hello $name" }
def person = personMock.proxyInstance()
// End Setup
// Exercise (can not change)
def closureMethod = person.&sayHello.curry("Groovy!")
closureMethod()
// End Exercise
personMock.verify(person)
Which would be the safest and simplest way to fix the test?
Currently, the test fails with java.lang.UnsupportedOperationException
Even when I am testing against a Interface, nothing prevents me from creating a mock class that implements the interface and do a poor-men verify demands.
import groovy.mock.interceptor.*
// I am testing against a interface, not an actual class
// this is not negociable.
interface Person {
void sayHello(name);
}
class PersonMock implements Person {
def calls = []
void sayHello(name) { calls << "sayHello" }
}
// Setup (can do whatever I need)
def person = new PersonMock()
// End Setup
// Exercise (can not change)
def closureMethod = person.&sayHello.curry("Groovy!")
closureMethod()
// End Exercise
assert person.calls == ['sayHello']

How to reuse feature methods in a #Stepwise Spock specification?

I have two Spock specifications, both test a long procedure from a different starting point, so it's like
#Stepwise
class FooSpec extends Specification {
def "setup1"() {...}
def "setup2"() {...}
def "common1"() {...}
def "common2"() {...}
...
}
#Stepwise
class BarSpec extends Specification {
def "setup3"() {...}
def "setup4"() {...}
def "common1"() {...}
def "common2"() {...}
...
}
Now I'd like to refactor my code to deduplicate all the common* feature methods, that are to be executed after the different setups.
I tried to use subclassing, but the superclass' feature methods are executed before and not after the subclass' ones. I also tried to write an own Spock extension (Spock version 0.7 for Groovy 2), but couldn't find a way to implement my desired behaviour there.
Consulting the source code of StepwiseExtension, I finally managed to come up with my own solution:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#ExtensionAnnotation(BeforeSuperExtension)
#interface BeforeSuper {}
This annotation marks feature methods in a #Stepwise test, that should be executed before super's feature methods.
The extension implementation will rearrange the execution order accordingly:
class BeforeSuperExtension extends AbstractAnnotationDrivenExtension<BeforeSuper>
{
def beforeSuper = []
#Override
void visitFeatureAnnotation(BeforeSuper annotation, FeatureInfo feature)
{
beforeSuper << feature
}
#Override
void visitSpec(SpecInfo spec)
{
def superFeatures = spec.superSpec.allFeaturesInExecutionOrder
def afterSuper = spec.features - beforeSuper
(beforeSuper + superFeatures + afterSuper).eachWithIndex { f, i ->
f.executionOrder = i
}
}
}
Put the common* methods in a base class, and add two subclasses with a setupSpec() method (instead of the setup* methods).
I've implemented the opposite strategy, with an annotation #AfterSubSpec that tells common methods in the superclass to run after methods in the subclass:
class AfterSubSpecExtension extends AbstractAnnotationDrivenExtension<AfterSubSpec> {
def afterSub = []
#Override
void visitFeatureAnnotation(AfterSubSpec annotation, FeatureInfo feature) {
afterSub << feature
}
#Override
void visitSpec(SpecInfo spec) {
def subSpecFeatures = spec.bottomSpec.allFeaturesInExecutionOrder - afterSub
(subSpecFeatures + afterSub).eachWithIndex { f, i -> f.executionOrder = i }
}
}

ExpandoMetaClass - Static Methods + singleton + overloaded functions

Using ExpandoMetaClass Static Methods can be added dynamically, how can i use this ExpandoMetaClass in Singleton object, with overloaded static function in it, let say the sample program need to be re written using ExpandoMetaClass whats needs to changed in the below program
#Singleton
class testA {
def static zMap = [:]
static def X() {
Y()
}
static def Y() {
}
static def X(def var) {
Y(var)
}
static def Y(def var) {
zMap.put(var)
}
}
One of the reasons to use a singleton is to avoid having static state and methods in a class. If you're using #Singleton, there's no reason to have static methods or fields. The way to use a singleton is like this:
#Singleton class TestA {
def someField = "hello"
def methodX() {
someField
}
}
println TestA.instance.methodX()
You can extend the singleton using ExpandoMetaClass like so:
TestA.instance.metaClass.newMethod = { -> "foo" }
TestA.instance.metaClass.methodX = { -> "goodbye" }
println TestA.instance.newMethod()
println TestA.instance.methodX()
If you really want a static method, you can do something like this:
TestA.metaClass.static.methodY = { -> "I am static" }
println TestA.methodY()
Note that if you override the class metaClass, rather than the instance metaClass, it won't apply to the instance if the instance has already been created. To get around this use #Singleton(lazy = true) and override the metaClass before accessing the instance.

Mocking methods of local scope objects with Mockito

I need some help with this:
Example:
void method1{
MyObject obj1=new MyObject();
obj1.method1();
}
I want to mock obj1.method1() in my test but to be transparent so I don't want make and change of code.
Is there any way to do this in Mockito?
The answer from #edutesoy points to the documentation of PowerMockito and mentions constructor mocking as a hint but doesn't mention how to apply that to the current problem in the question.
Here is a solution based on that. Taking the code from the question:
public class MyClass {
void method1 {
MyObject obj1 = new MyObject();
obj1.method1();
}
}
The following test will create a mock of the MyObject instance class via preparing the class that instantiates it (in this example I am calling it MyClass) with PowerMock and letting PowerMockito to stub the constructor of MyObject class, then letting you stub the MyObject instance method1() call:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class MyClassTest {
#Test
public void testMethod1() {
MyObject myObjectMock = mock(MyObject.class);
when(myObjectMock.method1()).thenReturn(<whatever you want to return>);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(myObjectMock);
MyClass objectTested = new MyClass();
objectTested.method1();
... // your assertions or verification here
}
}
With that your internal method1() call will return what you want.
If you like the one-liners you can make the code shorter by creating the mock and the stub inline:
MyObject myObjectMock = when(mock(MyObject.class).method1()).thenReturn(<whatever you want>).getMock();
If you really want to avoid touching this code, you can use Powermockito (PowerMock for Mockito).
With this, amongst many other things, you can mock the construction of new objects in a very easy way.
No way. You'll need some dependency injection, i.e. instead of having the obj1 instantiated it should be provided by some factory.
MyObjectFactory factory;
public void setMyObjectFactory(MyObjectFactory factory)
{
this.factory = factory;
}
void method1()
{
MyObject obj1 = factory.get();
obj1.method();
}
Then your test would look like:
#Test
public void testMethod1() throws Exception
{
MyObjectFactory factory = Mockito.mock(MyObjectFactory.class);
MyObject obj1 = Mockito.mock(MyObject.class);
Mockito.when(factory.get()).thenReturn(obj1);
// mock the method()
Mockito.when(obj1.method()).thenReturn(Boolean.FALSE);
SomeObject someObject = new SomeObject();
someObject.setMyObjectFactory(factory);
someObject.method1();
// do some assertions
}
Both mocking of a new instance creation and static methods is possible without PowerMock in the latest mockito versions and junit5.
Take a look in the methods Mockito.mockConstruction() and Mockito.mockStatic().
In your case:
try (MockedConstruction<MyObject> myobjectMockedConstruction = Mockito.mockConstruction(MyObject.class,
(mock, context) -> {
given(mock.method1()).willReturn("some result"); //any additional mocking
})) {
underTest.method1();
assertThat(myobjectMockedConstruction.constructed()).hasSize(1);
MyObject mock = myobjectMockedConstruction.constructed().get(0);
verify(mock).method1();
}
You could avoid changing the code (although I recommend Boris' answer) and mock the constructor, like in this example for mocking the creation of a File object inside a method. Don't forget to put the class that will create the file in the #PrepareForTest.
package hello.easymock.constructor;
import java.io.File;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({File.class})
public class ConstructorExampleTest {
#Test
public void testMockFile() throws Exception {
// first, create a mock for File
final File fileMock = EasyMock.createMock(File.class);
EasyMock.expect(fileMock.getAbsolutePath()).andReturn("/my/fake/file/path");
EasyMock.replay(fileMock);
// then return the mocked object if the constructor is invoked
Class<?>[] parameterTypes = new Class[] { String.class };
PowerMock.expectNew(File.class, parameterTypes , EasyMock.isA(String.class)).andReturn(fileMock);
PowerMock.replay(File.class);
// try constructing a real File and check if the mock kicked in
final String mockedFilePath = new File("/real/path/for/file").getAbsolutePath();
Assert.assertEquals("/my/fake/file/path", mockedFilePath);
}
}
If you don't prefer to use PowerMock, you may try the below way:
public class Example{
...
void method1(){
MyObject obj1 = getMyObject();
obj1.doSomething();
}
protected MyObject getMyObject(){
return new MyObject();
}
...
}
Write your test like this:
#Mock
MyObject mockMyObject;
#Test
void testMethod1(){
Example spyExample = spy(new Example());
when(spyExample.getMyObject()).thenReturn(mockMyObject);
//stub if required
doNothing().when(mockMyObject.doSomething());
verify(mockMyObject).doSomething();
}
You can do this by creating a factory method in MyObject:
class MyObject {
public static MyObject create() {
return new MyObject();
}
}
then mock that with PowerMock.
However, by mocking the methods of a local scope object, you are depending on that part of the implementation of the method staying the same. So you lose the ability to refactor that part of the method without breaking the test. In addition, if you are stubbing return values in the mock, then your unit test may pass, but the method may behave unexpectedly when using the real object.
In sum, you should probably not try to do this. Rather, letting the test drive your code (aka TDD), you would arrive at a solution like:
void method1(MyObject obj1) {
obj1.method1();
}
passing in the dependency, which you can easily mock for the unit test.

Cannot dynamically change or add methods in a class using GroovyClassLoader

I try to dynamically change and add methods of a class defined in a groovy script from another groovy script but cannot figure out why it works if I use the classname directly in .metaClass. but not if I load the class using the GroovyClassLoader(which I need to do!).
In one file 'MyTest.groovy' I have
class MyTest {
public void setUp() {
println "SET UP"
}
public void tearDown() {
println "TEAR DOWN"
}
public void testA() {
println "testA"
}
}
and another file 'suite.groovy' contains
#!/usr/bin/env groovy
public class MyTestSuite {
// For debug
public static printClassLoader(Class cls) {
ClassLoader loader = cls.classLoader
while (loader) {
println loader.class
println loader.URLs.join("\n")
println "\n\n"
loader = loader.parent
}
}
public static void suite() {
// First method to define my class (change/addition of methods works)
//Class testClass = MyTest
// Second way to define my class (change/addition of methods doesn't work)
ClassLoader parent = MyTestSuite.class.getClassLoader();
GroovyClassLoader gcl = new GroovyClassLoader(parent);
Class testClass = gcl.parseClass(new File("MyTest.groovy"));
printClassLoader(testClass)
testClass.metaClass.setUp = {-> println "I'm your new setUp()" ;}
testClass.metaClass.newTest = {-> println "I'm your new newTest()" ; }
}
}
MyTestSuite.suite()
MyTest aTest = new MyTest()
aTest.setUp()
aTest.newTest()
With the first method I get the expected result:
I'm your new setUp()
I'm your new newTest()
But with the second one I get
SET UP
Caught: groovy.lang.MissingMethodException: No signature of method: MyTest.newTest() is applicable for argument types: () values: []
Possible solutions: testA(), getAt(java.lang.String), wait(), inspect(), every()
at suite.run(suite.groovy:34)
Interestingly modifying an existing method doesn't work but there is no exception but trying to add a new one throws one.
I reckon it has to do something with the class loaders used but couldn't figure what exactly and what to change!
For the first version here are the class loaders called:
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class org.codehaus.groovy.tools.RootLoader
class sun.misc.Launcher$AppClassLoader
class sun.misc.Launcher$ExtClassLoader
For the second version:
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class org.codehaus.groovy.tools.RootLoader
class sun.misc.Launcher$AppClassLoader
class sun.misc.Launcher$ExtClassLoader
Any idea welcome!
Franck
The new GroovyClassLoader is not the Groovy classloader of the current thread.
It will be disposed after the suite() method finishes - along with its own Class and MetaClass associations.
However, this works:
Class testClass = gcl.parseClass(new File("MyTest.groovy"));
testClass = Class.forName(testClass.getName())

Resources