How to test class with #Autowired using Spock - grails

I have a class in src/groovy like this
public class MyClass {
#AutoWired
SomeOtherClass someOtherClass
String test() {
return someOtherClass.testMethod()
}
}
When I write a test for this method I am getting an error: Cannot invoke method testMethod() on null object.
This is my test :-
def "test test" () {
expect:
myClass.test() == "somevalue"
}
What am I doing wrong? Is there a way to mock the #Autowired class?

You need to mock your someOtherClass. Something like this
def "test test"(){
setup:
myClass.someOtherClass = Mock(SomeOtherClass)
myClass.someOtherClass.testMethod() >> "somevalue"
expect:
myClass.test() == "somevalue"
}

Though the previous answer should work, spock provide more elegant way of injecting beans as per need. You could use doWithSpring closure to declare beans just like spring dsl support provided in grails using resources.groovy.
class MyClass extends Specification{
def setup(){
static doWithSpring={
someOtherClass(SomeOtherClass)
//declare below if want to inject myClass somewhere else as a bean else not
/*myClass(MyClass){bean->
someOtherClass = someOtherClass
}*/
}
}
def "test test" () {
expect:
myClass.test() == "somevalue"
}
}

Related

Problems in mocking a factory in micronaut

I am fairly new to micronaut and currently i am stuck in a strange situation where i am unable to mock a factory for a value.
So i have an interface
#Qualifier
#Retention(RUNTIME)
public #interface SomethingToInject {
}
and then i have a factory for this where i am annotating a method with #SomethingToInject
::
#Factory
public class MyFactory {
private String someValue;
#Singleton
#SomethingToInject
public String getSomeValue(){
return someValue;
}
#Scheduled(fixedDelay = "24h", initialDelay = "5s")
public void refreshSomeValue() throws IOException {
// An api call to fetch this new SomeValue
SomeValue = apiResponse;
}
}
Now I am injecting this to wherever i wish to use this someValue
For example
#Singleton
public class MyService{
#Inject
#SomethingToInject
private String someValue;
// service functions...
}
but when i am writing tests for MyService functions it says :
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type myService
Message: Bean Factory MyFactory returned null
how do i mock the factory? I have tried to mock the factory with mockbean and also with replaces but maybe i am missing a trick here.
I am guessing the problem here is that the #SomethingToInject is has retention runtime?
my tries in MyServiceTest:
#MockBean(SomethingToInject)
SomethingToInject somethingToInject(){
return mock(SomethingToInject.class)
}
#Factory
#Replaces(MyFactory.class)
public class CustomFactory {
private String someValue;
#Singleton
#SomethingToInject
public String getSomeValue(){
return "dummyValue";
}
}
but it doesn't work as it throws the same error of injection not working with additional message of :
CustomFactory: method 'void <init>()' not found

Micronaut #Replaces with declarative Client

I am going to use the code from Micronaut Documentation (Declarative Http Client)- And I'm using Spock
PetOperations.java
#Validated
public interface PetOperations {
#Post
Single<Pet> save(#NotBlank String name, #Min(1L) int age);
}
I have a declarative client:
#Client("/pets")
public interface PetClient extends PetOperations {
#Override
Single<Pet> save(String name, int age);
}
My goal is when I run a test class, I want to call (#Replaces) another class (PetDummy) instead of the PetClient, PetDummy class is located in my test folder
#Primary
#Replaces(PetClient.class)
#Singleton
public class PetDummy implements PetOperations {
#Override
public Single<Pet> save(String name, int age) {
Pet pet = new Pet();
pet.setName(name);
pet.setAge(age);
// save to database or something
return Single.just(pet);
}
}
test class:
class PetTest extends Specification {
#Shared
#AutoCleanup
ApplicationContext applicationContext = ApplicationContext.run();
//EmbeddedServer server = applicationContext.getBean(EmbeddedServer.class).start();
PetClient client = applicationContext.getBean(PetOperations.class);
def 'test' (){
given: 'name and age'
when:
client.save("Hoppie", 1);
then:
noExceptionThrown()
}
}
However, at the end PetClient is called, I have as well tried with the #Factory annotation, but no success
PetClient extends PetOperations and PetDummy implements PetOperations, if they both implement then it will make sense to use #Replaces ...
Is there something else I can try out?
Thank you!
Another Issue:
Now that it works, the PetClient is a dependency in my PetService. When I test my PetService, it still calls the PetClient instead of the PetDummy.
I assume it has to do with the applicationContext, you will see
PetService:
PetService {
#Inject
PetClient client;
buyFood(){
//...
Single<Pet> pet = client.save("Hoppie", 1));
}
}
PerService Test:
class PetServiceTest extends ApplicationContextSpecification {
#Subject
#Shared
PetService petService = applicationContext.getBean(PetService)
PetOperations client = applicationContext.getBean(PetOperations.class) //client is not used here
def 'test' (){
given:
when:
petService.buyFood()
then:
noExceptionThrown()
}
}
I think that I need to "get into" the applicationContext from the PetService, to tell "use the PetDummy" implementation (Inside the test class, because the ApplicationContextSpecification belong to another module
The ApplicationContextSpecification is:
abstract class ApplicationContextSpecification extends Specification implements ConfigurationFixture {
#AutoCleanup
#Shared
ApplicationContext applicationContext = ApplicationContext.run(configuration)
/* def cleanup() {
assert !hasLeakage()
}*/
}
The ConfigurationFixture contains the properties for the database(hibernate)
You are already retrieving the PetClient bean implementation:
PetClient client = applicationContext.getBean(PetOperations.class);
Which should provide the replacing dummy bean implementation if called with the appropriate type:
PetOperations client = applicationContext.getBean(PetOperations.class);

Spock fails when PostConstruct calls a injected service

Can any one tell me how to solve the issue of PostConstruct get called before mocking:
Service:
class MyService {
SecondService secondService // injected
#PostConstruct
void init() {
myFunction()
}
void myFunction() {
secondService.doSomething()
}
}
Test:
#TestFor(MyService)
class MyServiceSpec extends Specification {
void "testing my service"() {
given:
MyService service = GroovySpy(MyService) {
myFunction() >> null
}
then:
true
}
}
Gives following error:
Invocation of init method failed; nested exception is java.lang.NullPointerException: Cannot invoke method doSomething() on null object
If you have #TestFor(MyService) - MyService instance will be created automatically and you can use it as 'service'. And you don't need to create MyService manually.
So you can only delete #TestFor(MyService) or use it and remove MyService service.
But you also need to correctly mock 'secondService'
#FreshRuntime
#TestFor(MyService)
class MyServiceSpec extends Specification {
def secondService = GroovyMock(SecondService)
def doWithSpring = {
secondService(InstanceFactoryBean, secondService, SecondService)
}
void "testing my service"() {
when:
service.myFunction()
then:
1 * secondService.doSomething()
}
}

Can i inject services into urlmappings?

Is it possible to inject a service in UrlMappings.groovy? Something like below...
MyService.groovy
class MyService {
String foo() {
return "test"
}
}
UrlMappings.groovy
class UrlMappings {
def myService
static mappings = {
"/${myService.foo()}"
}
}
I am using Grails 3.0.11
Thank you

Dependency Injection with PowerMock & Mockito

How do I create a JUnit testcase for the following class with PowerMock & Mockito.
The class I want to inject is a final class so I'll need to use PowerMock to mock it.
Also note I would prefer to use DI rather than a setter to inject it.
import javax.inject.Inject;
public class ObjectA {
// Use DI to Inject a mock for this 'final' class
#Inject
private ObjectB objectB;
public ObjectA() {
}
public void someMethod() {
if (null == this.objectB) {
throw new IllegalStateException("Failed to inject ObjectB");
}
this.objectB.someOtherMethod();
}
}
No need for PowerMock at this point. Mockito can do all the work.
public class ObjectATest
{
#Mock
private ObjectB objectB;
#InjectMocks
private ObjectA objectA;
#Before
public void setup()
{
MockitoAnnotations.initMocks(this);
}
#Test
public void test()
{
try
{
objectA.someMethod();
}
catch(IllegalStateException e)
{
Assert.fail();
}
}
}
You can use the Whitebox class. For example let's say you've created a mock of ObjectB called objectBMock and an instance of ObjectA called objectA:
Whitebox.setInternalState(objectA, objectBMock);
This will "inject" objectBMock to objectA.

Resources