Micronaut #Replaces with declarative Client - spock

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);

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 (continue)

I have the following scenario:
A declarative Client
#Client("/pets")
public interface PetClient extends PetOperations {
#Override
Single<Pet> save(String name, int age);
}
A PetDummy class, which #Replaces the PetClient during for testing
#Primary
#Replaces(PetClient.class)
#Singleton
public class PetDummy implements PetOperations {
#Override
public Single<Pet> save(String name, int age) {
// do something
return Single.just(pet);
}
}
And a PetService class that has the declarative client as dependency
PetService {
#Inject
PetClient client;
buyFood(){
//...
Single<Pet> pet = client.save("Hoppie", 1));
}
}
When I test my PetService, my goal is that the test calls the PetDummy class instead of the PetClient
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) //somehow i need to tell the application context to use the PetDummy class
def 'test' (){
given:
when:
petService.buyFood()
then:
noExceptionThrown()
}
}
I think that I need to "get into" the applicationContext from the PetService. However, the ApplicationContextSpecification belongs to another module, so it won't recognise the PetDummy implementation
The ApplicationContextSpecification is:
abstract class ApplicationContextSpecification extends Specification implements ConfigurationFixture {
#AutoCleanup
#Shared
ApplicationContext applicationContext = ApplicationContext.run(configuration)
}
The ConfigurationFixture contains the properties for the database(hibernate)

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.

Cannot invoke method render() on null object in Grail while email sending

I am using mail:1.0.1 plugin for mail sending
but while sending mail its gives me an error..
Source :-
def serviceMethod(EmailModel mailObj) {
PageRenderer groovyPageRenderer;
try{
sendMail {
to "abc#gmail.com"
subject mailObj.subject;
html groovyPageRenderer.render(template:"myMailTemplate", model: [mailObj: mailObj])
}
} catch (Throwable th) {
th.printStackTrace();
}
}
If you want to send the gsp page as email body then you can send it like:
def mailService
def serviceMethod(EmailModel mailObj) {
...
mailService.sendMail {
to email
subject "subject"
body(view: "/_template", model: [mailObj: mailObj])
}
...
}
EDIT...................................................................................
Just inject PageRenderer groovyPageRenderer globally, like
import grails.gsp.PageRenderer
class TestService {
PageRenderer groovyPageRenderer
def getText() {
String s = groovyPageRenderer.render(template: "../first/temp", model: [name: 'user1690588'])
println "Content = ${s}"
}
}
I think you are calling Service Class(.groovy) method from java class.
by using object of EmailService class.
So you cant get Object of PageRenderer class.
for this
Create SpringsUtil Class in src/java and define constant object of EmailSerevice. like this
public class SpringsUtil {
public static ApplicationContext getCtx() {
return getApplicationContext();
}
public static ApplicationContext getApplicationContext() {
return (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT);
}
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) getApplicationContext().getBean(beanName);
}
public static final String EMAIL_SERVICE = "emailService";
// public static final String INVENTORY_REORDER_SERVICE = "InventoryReorderService";
}
create object of Service class and call method
EmailService emailService = SpringsUtil.getBean(SpringsUtil.EMAIL_SERVICE);

Jersey #Context scope

I have a hard time understanding the injection mechanism of Jersey. The JAX-RS Specification (http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-520005) states that injection via #Context is possible in Application subclasses, root resource classes and providers.
I now have a class that is instantiated at startup and has a method which is called on every request. Inside the method I need access to the current UriInfo object. The problem is, that this method is not called from my code. So I can't pass UriInfo directly to the method.
I actually want to do something like this:
public class MyClass implements ThirdPartyInterface {
// not possible because class is no Application subclass, root resource class or provider
#Context
private UriInfo uriInfo;
public void methodCallebByThirdPartyCode() {
Uri requestUri = uriInfo.getRequestUri();
// do something
}
}
I tried this. Obviously with no success:
public class MyClass implements ThirdPartyInterface {
private UriInfo uriInfo;
public MyClass(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
public void methodCallebByThirdPartyCode() {
Uri requestUri = uriInfo.getRequestUri();
// do something
}
}
#Provider
#Produces(MediaType.WILDCARD)
public class MyBodyWriter implements MessageBodyWriter<MyView> {
#Context
private UriInfo uriInfo;
private MyClass myClass;
private ThirdPartyClass thirdPartyClass;
public MyBodyWriter() {
// uriInfo is null at this time :(
myClass = new MyClass(uriInfo);
thirdPartyClass = new ThirdPartyClass();
thirdPartyClass.register(myClass);
}
public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException {
// execute() calls MyClass#methodCallebByThirdPartyCode()
thirdPartyClass.execute();
}
}
The only workaround I can think of is this. I don't think it's very clean:
public class MyClass implements ThirdPartyInterface {
private UriInfo uriInfo;
public void setUriInfo(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
public void methodCallebByThirdPartyCode() {
Uri requestUri = uriInfo.getRequestUri();
// do something
}
}
#Provider
#Produces(MediaType.WILDCARD)
public class MyBodyWriter implements MessageBodyWriter<MyView> {
#Context
private UriInfo uriInfo;
private MyClass myClass;
private ThirdPartyClass thirdPartyClass;
public MyBodyWriter() {
myClass = new MyClass();
thirdPartyClass = new ThirdPartyClass();
thirdPartyClass.register(myClass);
}
public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException {
myClass.setUriInfo(uriInfo);
// execute() calls MyClass#methodCallebByThirdPartyCode()
thirdPartyClass.execute();
myClass.setUriInfo(null);
}
}
I hope there is a better solution, but maybe I'm completely on the wrong track.
Thanks!
Late answer, but a good question ... so lets go:
You can use a org.glassfish.hk2.api.Factory and javax.inject.Provider for injections. I don't know since which version this is available, so maybe you have to upgrade your jersery version. For the following samples i used jersey 2.12.
First you have to implement and register/bind a Factory for your MyClass:
MyClassFactory:
import javax.inject.Inject;
import javax.ws.rs.core.UriInfo;
import org.glassfish.hk2.api.Factory;
// ...
public class MyClassFactory implements Factory<MyClass> {
private final UriInfo uriInfo;
// we will bind MyClassFactory per lookup later, so
// the constructor will be called everytime we need the factory
// meaning, uriInfo is also per lookup
#Inject
public MyClassFactory(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
#Override
public MyClass provide() {
return new MyClass(uriInfo)
}
#Override
public void dispose(UriInfo uriInfo) {
// ignore
}
}
Registration via ResourceConfig:
import org.glassfish.hk2.api.PerLookup;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
// ...
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(MyClassFactory.class).to(MyClass.class).in(PerLookup.class);
// ... bind additional factories here
}
});
// ...
}
}
Now you are able to inject MyClass per lookup to providers, resources etc.
But Attention: Afaig there are two approaches and only one will work as eventually aspected for providers ...
import javax.inject.Inject;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
// ...
#Provider
#Produces("application/foo-bar")
public class MyBodyWriter implements MessageBodyWriter<MyView> {
// first approache - don't do it!
// will only injected once, cause MyBodyWriter is only instantiated once
#Inject
private MyClass myClass;
// second approache - works fine!
private final javax.inject.Provider<MyClass> provider;
// MyBodyWriter instantiate once
// get an inject provider here
#Inject
public MyBodyWriter(javax.inject.Provider<MyClass> myClassProvider) {
this.provider = myClassProvider;
}
#Override
public boolean isWriteable(Class<?> t, Type g, Annotation[] a, MediaType m) {
return t == MyView.class;
}
#Override
public long getSize(MyView t, Class<?> c, Type g, Annotation[] a, MediaType m) {
// deprecated by JAX-RS 2.0 and ignored by Jersey runtime
return 0;
}
#Override
public void writeTo(MyView v, Class<?> c, Type t, Annotation[] a, MediaType m, MultivaluedMap<String, Object> s, OutputStream o) throws IOException, WebApplicationException {
// attention: its not per lookup !!!
MyClass myClassDirectInjected = myClass;
System.out.println(myClassDirectInjected); // same instance everytime
// but this is ;)
MyClass myClassFromProvider = provider.get();
System.out.println(myClassFromProvider); // it's a new instance everytime
// ...
}
}
Hope this was somehow helpfull.

Resources