Test class which depends on Guice Provider<T> - java

How to test a class which depends on Provider<>?
Please see the code below.
class ToTest {
#Inject
Provider<Processor> processorProvider;
public buildData() {
processorProvider.get().process();
}
class ProcessorProviderImpl implements Provider<Processor> {
#Inject
private Handler someHandler;
public Processor get() {
return new MyProcessor(somehandler)
}
}
public static class TestModule extends JukitoModule {
#Override
protected void configureTest() {
bind(Processor.class).toProvider(
ProcessorInstanceProviderImpl.class);
bindMock(SubHandler.class).in(TestSingleton.class);
}
}
class Handler {
#Inject
private SubHandler subHandler; // this is singleton instance
}
}
So when I mock subHandler it doesn't work and when I run unit test I am getting a NullPointerException where subHandler.handle() is getting called.

You can use Providers.of() to initialize processorProvider with a provider of your collaborator instance.
https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/util/Providers.html
test = new ToTest();
test.processorProvider = Providers.of(processorMock);

Related

How to get one instance of dependency while it injected several times in different classes?

I need to get one instance of OwnerService, because in Dataloader class I load some data to that instance and in OwnerController class I have to get loaded data. But in OwnerController there was no data. I printed out the instances and receive different ID of instances
Dataloader class
public class DataLoader implements CommandLineRunner {
private final OwnerService ownerService;
public DataLoader() {
ownerService = new OwnerServiceMap();
}
#Override
public void run(String... args) throws Exception {
System.out.println(ownerService);
}
}
#RequestMapping("/owners")
#Controller
public class OwnerController {
private final OwnerService ownerService;
public OwnerController(OwnerService ownerService) {
this.ownerService = ownerService;
}
#GetMapping({"", "/", "/index"})
public String ownersIndex(Model model) {
System.out.println(ownerService);
model.addAttribute("owners", ownerService.findAll());
return "owners/index";
}
}
I need one instance of Bean in several injected classes.
In your class DataLoader, you are not injecting OwnerService. Instead, the constructor directly creates an instance of class OwnerServiceMap (which is presumably a class that implements interface OwnerService):
public DataLoader() {
ownerService = new OwnerServiceMap();
}
Instead, inject it into DataLoader, in exactly the same way as you are doing in OwnerController:
public DataLoader(OwnerService ownerService) {
this.ownerService = ownerService;
}

Mocking constructor using PowerMockito doesn't work

I want to test a method which creates an object of another class using it's parameterized constructor. Even though I've mocked the constructor of MyClass, it makes the third party library which is in constructor implementation and results in the error. I'm using Mockito/PowerMockito.
public class MyClass{
private MyObj obj;
MyClass (String profile)
{
//some 3rd party library call
obj = thridPartyLib.someMethod(profile);
}
public String someMethod(){
return obj.someExternalCall();
}
}
Class which I want to test
public class ClassTobeTested{
public void execute(){
//some code
// ......
MyClass myClass = new MyClass(profile);
myclass.someMethod();
}
}
What I tried so far - classUnderTest.execute() ends up calling the thridPartyLib.someMethod(profile); which is part of MyClass constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = new ClassTobeTested();
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute(){
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
Your code will work only if you are working with a spy or mock of classUnderTest. Try this. This should work
#RunWith(PowerMockRunner.class)
#PrepareForTest( {MyClass.class, ClassTobeTested.class })
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = spy(new ClassTobeTested());
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute() throws Exception {
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
The pain might suggest another approach. Consider injecting a Factory into ClassTobeTested which knows how to create an instance of MyObj. For example:
class MyObjFactory {
MyObj create(String profile) {
return new MyClass(profile);
}
}
then
public class ClassTobeTested {
private final MyObjFactory factory;
public ClassTobeTested(MyObjFactory factory) {
this.factory = factory;
}
public void execute(){
//some code
// ......
// MyClass myClass = new MyClass(profile);
MyClass myClass = factory.create(profile);
myclass.someMethod();
}
}
so the unit test becomes simpler with only having to mock the Factory and have it return a mocked MyClass instance. Then it's simple to verify myclass.someMethod() was invoked as expected.

GWT google-gin field injection not working

I'm trying to get field injecting to work in google-gin, but when I call TestClass.test() the injected field is null. What am I doing wrong? According to the docs field injection should be really straight forward. Is there anything I'm missing in the ContextModule class?
public class MainEntry implements EntryPoint {
private final ContextInjector injector = GWT.create(ContextInjector.class);
#Override
public void onModuleLoad() {
injector.getAppMain();
}
}
#GinModules(ContextModule.class)
public interface ContextInjector extends Ginjector {
AppMain getAppMain();
}
public class MyLogger {
}
public class ContextModule extends AbstractGinModule {
#Override
protected void configure() {
bind(MyLogger.class).in(Singleton.class);
}
}
public class AppMain {
#Inject
AppMain(MyLogger logger) {
// logger is injected properly here
new TestClass().test();
}
}
public class TestClass {
#Inject
private MyLogger logger;
public void test() {
// logger is null here!
}
}
Your TestClass is not managed by GIN, so GIN won't inject anything in it. You have to either let GIN instantiate TestClass (e.g. change MyLogger to TestClass in your AppMain constructor, and call test() on the given instance), or ask GIN to inject an existing TestClass instance's members (add a method to your Ginjector that takes a TestClass as argument, when called, it'll inject fields and methods of the passed-in instance).

Dependency injection in my singleton class

Let's say I have interface Bar:
public interface Bar {
void lengthyOperation ();
}
and it's implementation Foo:
#Service
public class Foo implements Bar {
void lengthyOperation () {
// lengthy operation implementation
}
}
I also have a singleton class called MyClass:
public class MyClass implements Runnable {
#Autowired private final Bar bar;
private final Thread thread;
private static MyClass instance;
private MyClass () {
thread = new Thread (this);
thread.start();
}
public static MyClass getInstance () {
if (instance == null) instance = new MyClass();
return instance;
}
public void run() {
while (true) {
bar.lengthyOperation();
Thread.sleep(5000);
}
}
}
How can I inject Bar into MyClass using #Autowired annotation (or any other way if possible)? I tried with #Autowired private final Bar bar; but it's always null;
If that can't be achieved, is there a way to prevent calling #Autowired constructor twice? If you don't know what I mean let me show you. This code:
#Controller
public class MyClass implements Runnable {
private final Bar bar;
#Autowired
public MyClass (Bar bar) {
this.bar = bar;
thread = new Thread (this);
thread.start();
}
public void run() {
System.out.println("New thread...");
while (true) {
bar.lengthyOperation();
Thread.sleep(5000);
}
}
}
would print out "New thread..." two times in console.
Maybe (probably) there is more gracious way of doing this, but I don't know about it... Any help would be appreciated!
Thank you!
EDIT #1 dimoniy asked how I make instance of my class. Basically, instance of MyClass has to be created on WebApp startup, so I used this code:
#Component
public class StartMyClass implements ApplicationListener<ApplicationEvent> {
public void onApplicationEvent(ApplicationEvent e) {
MyClass.getInstance();
}
}
How do you create your instance of MyClass?
The #Autowired does not work because your MyClass instance is not managed by Spring. You need to create MyClass instance in your Java/XML spring configuration or annotate it with #Component annotation and make sure that MyClass's package is scannable by spring.
Your annotation with #Controller is not correct since your class is clearly not a controller...
For example:
#Configuration
public class MiscConfiguration {
#Bean
public MyClass myClass() {
return new MyClass();//Will be created/managed by Spring, #Autowired will work
}
}

Mockit redefineMethod not working because of interface or generic abstract

I'm trying to figure out why Mockit is not working for the following code:
public class TestClass {
#Test
public void test() {
Mockit.redefineMethods(ExecuterClass.class, new Object() {
#SuppressWarnings("unused")
public SomeService getService() {
return new MockSomeServiceImpl();
}
});
// Code to run test
}
}
public abstract class ExecuterClass<T,U,V,W> {
// Other methods/variables
public SomeService getService() {
return someProvider.getService();
}
}
public interface SomeService {
// Some method definitions
}
public class MockSomeServiceImpl implements SomeService {
// Some method implementations
}
The error I get back is:
java.lang.IllegalAccessError: tried to access class TestClass from class ExecuterClass
Any ideas on how to fix this?? In the end, I would like the test to use the MockSomeServiceImpl methods rather than those in SomeService implementation.
SomeService was generated by a WSDL, so I don't have the implementation that someObject.getService() returns. So I can't do Mockit.redefineMethods(SomeServiceImpl.class, MockSomeServiceImpl.class)

Categories