Using Guice Module class to setup entire JavaClient - java

Hello everyone I have this problem where I want to set up the entire Client setup inside a Guice module and then call it inside a clientSetup method in testing class.
What I am struggling with is how to abstract it even more.
Code I currently have:
JavaClient client;
public void clientSetup (param1, param2) {
final String var1;
Injector injector = createInjector(
new TestProviderModule()
};
var1 = injector.getInstance(Key.get(String.class, Names.named("var1Name")));
if (!value.equals("Dev")) {
System.setProperty(var1);
}
final String var2 = String.format("%s.%s", param1, param2);
this.client = injector.getInstance(ClientFactory.class).getTestingClient(var2);
}
I also have a TestProviderModule class which looks like this:
public class TestingModuleProvider extends AbastractModule {
#Override
protected void configure() {
};
#Provides
#Singleton
#Named("var1name")
String getVar1 () {
method that compares var1 based on blah blah
return var1;
}
#Provides
#Singleton
ClientFactory getFactory () {
return new ClientFactory();
}
}
This is my ClientFactory class.
public class ClientFactory {
public GetJavaClient javaClientSetup (final string var2) {
return new ClientBuilder()
.remoteOf(GetJavaClient.class)
.withConfiguration(var2)
.newClient();
}
public GetInventoryJavaClient javaClientSetup (final string var2) {
return new ClientBuilder()
.remoteOf(GetInventoryJavaClient.class)
.withConfiguration(var2)
.newClient();
}
}
What I am trying to get is this where I have everything set up inside the Guice Module class and just inject it into the client. The reason I want that is because I have 3 different test suits and I do not want to duplicate the code but am not sure how to best extract everything.
JavaClient client;
public void clientSetup (param1, param2) {
Injector injector = createInjector(
new TestProviderModule()
};
this.client = injector.getInstance(ClientFactory.class).getTestingClient(var2);
}

Related

How do I write JUnit test to cover both branches of an if statement

New in JUnit here. I am using JUnit 4 with Mockito. How do I write junit for "if" condition?
Note: I am trying to cover inside the if statement when question is not null. Hopefully my question makes sense.
public class MyClass{
private HttpServletRequest request;
private A a;
private B b;
public void go(String something, String s){
MyQuestion question = Exam.getSubject().getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
// getMarks I do have catching an exception
Here is the snippet:
public class MarksClass{
Public MyQuestion getMarks(long idA, long IdB, String s){
try{
//some code
}catch(Exception e){
throw new SomeException("exception" + e);
}
}
}
Assuming, "getSubject" returns a field with name "subject".
final HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
ReflectionTestUtils.setField(myClass, "request", mockedRequest);
final MarksClass mockedMarksClass = Mockito.mock(MarksClass.class);
final MyQuestion mockedResult = Mockito.mock(MyQuestion.class);
Mockito.when(mockedMarksClass.getMarks(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString()).thenReturn(mockedResult);
ReflectionTestUtils.setField(myClass, "subject", mockedMarksClass);
//... rest of the test
Design your class in such a way that testing becomes easy. Or change the design so that it can be tested more easily.
Having global singletons makes testing difficult, if not impossible. The general way forward is to have a class injected with all its external dependencies (DI, dependency injection) or pass the dependencies as arguments to the method.
public class MyClass {
private HttpServletRequest request;
private A a;
private B b;
private final Supplier<Subject> subjectFactory;
public MyClass(final Supplier<Subject> subjectFactory) {
this.subjectFactory = subjectFactory;
}
public void go(String something, String s){
final MyQuestion question = subjectFactory.get().getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
Then in your real code, initialize the class with a method reference to the method on your singleton:
final MyClass myClass = new MyClass(Exam::getSubject);
And in your test inject a test double:
new MyClass(() -> new Subject() {
#Override
public MyQuestion getMarks(…) {
return null;
}
);
Of course, nothing is prevent you from changing the Supplier<Subject> to a Supplier<MyQuestion>, Function<String, MyQuestion>, or a custom interface; and then replacing this with a test double.
#FunctionalInterface
public interface Grader {
MyQuestion getMarks(String idA, String idB, String something);
}
public class MyClass {
private HttpServletRequest request;
private A a;
private B b;
private final Grader grader;
public MyClass(final Grader grader) {
this.grader = grader;
}
public void go(String something, String s){
final MyQuestion question = grader.getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
And then again in your production code vs your test code:
final MyClass production = new MyClass(Exam.getSubject()::getMarks);
final MyClass underTest = new MyClass((a, b, something) -> null);
Providing different implementations of this interface can make your code a bit more expressive:
public class ExamSubjectGrader implements Grader {
#Override
public MyQuestion getMarks(String idA, String idB, String something) {
return Exam.getSubject().getMarks(idA, idB, something);
}
}
public class NullGrader implements Grader {
#Override
public MyQuestion getMarks(String idA, String idB, String something) {
return null;
}
}
MyClass production = new MyClass(new ExamSubjectGrader());
MyClass underTest = new MyClass(new NullGrader());
(both of those are actually singletons, but they could have their own dependencies or state).
And as you can see: you don't even need a heavy mocking library such as Mockito. Good ol' Java can do that just fine.
Find more details in the question Why is my class not using my mock in unit test?

Injecting an object that requires enum in Guice

I have an object to be injected that is defined as:
public class EnvironmentModule extends AbstractModule {
#Override
protected void configure() {
}
#Provides
#Singleton
private String getObject(final Client client) {
...
}
}
Client is an enum defined as :
#NoArgsConstructor(force = true)
public enum Client {
private String name;
Client(final String name) {
this.name = name;
}
public static Client identifyClient(final String clientName) {
}
}
This gives me an error-
Could not find a suitable constructor in Client. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private
at Client.class(Client.java:5)
at EnvironmentModule.getObject(EnvironmentModule.java:35)
Please help. What has to be done.
The reason this is happening is because in your module you do not declare an instance of Client to be injected in the scope of the module, so it tries to create one with an empty constructor. This does not work because your enum has two constructors, and guice requires a single empty constructor. The solution to this to create a singleton of your client. I assume the code you omitted in Client looks like
public enum Client {
//I assume it works like this
NORMAL_CLIENT("whatever");
private String name;
Client(final String name) {
this.name = name;
}
public static Client identifyClient(final String clientName) {
return Arrays.stream(Client.values())
.filter(client -> clientName.equals(client.name))
.findAny()
//This is dangerous, throw an error if its not found
.get();
}
}
So we need to create a singleton in the environment module for the client. this would look like
public class EnvironmentModule extends AbstractModule {
#Override
protected void configure() {
super.configure();
}
#Provides
#Singleton
private Client getClient() {
return Client.identifyClient("whatever");
}
#Provides
#Singleton
private String doWhatever(final Client client) {
System.out.println("found client " + client);
return "cool it works";
}
}
invoking the module through
public class Main {
public static void main(String[] args) {
final var envInjector = Guice.createInjector(new EnvironmentModule());
final var client = envInjector.getInstance(Client.class);
final var doWhateverString = envInjector.getInstance(String.class);
System.out.println(doWhateverString);
System.out.println("found instance " + client);
}
}
we can see
found client NORMAL_CLIENT
cool it works
found instance NORMAL_CLIENT

junit - how to mock field in real class?

I have a tricky situation. I am using MVP architecture for android but thats not important. I have a class called DoStandardLoginUsecase that basically just connects to a server with login info and gets a access token. i am trying to test it. But the problem is the context that i am passing in to it so i can initialize dagger.
public class DoStandardLoginUsecase extends BaseUseCase {
#Inject
UserDataRepository mUserDataRepo;
private StandardLoginInfo loginInfo;
public DoStandardLoginUsecase(Context context) {
/* SEE HERE I AM USING A APPLICATION CONTEXT THAT I PASS TO DAGGER
*/
((MyApplication)context).getPresenterComponent().inject(this);
}
#Override
public Observable<Login> buildUseCaseObservable() {
return mUserDataRepo.doStandardLogin(loginInfo);
}
public void setLoginInfo(StandardLoginInfo loginInfo) {
this.loginInfo = loginInfo;
}
}
and here is the test i have so far:
public class DoStandardLoginUsecaseTest {
DoStandardLoginUsecase standardLoginUsecase;
StandardLoginInfo fakeLoginInfo;
TestObserver<Login> subscriber;
MockContext context;
#Before
public void setUp() throws Exception {
//now when i create the object since its a mock context it will fail when it tries to call real things as these are stubs. So how do i test this object. how do i create an instance of this object ? I am willing to use [daggerMock][1] if that helps also.
standardLoginUsecase = New DoStandardLoginUsecase(context);
fakeLoginInfo = new StandardLoginInfo("fred#hotmail.com","Asdfgh4534");
subscriber = TestObserver.create();
}
#Test
public void buildUseCaseObservable(){
standardLoginUsecase.seLoginInfo(fakeLoginInfo);
standardLoginUsecase.buildUseCaseObservable().subscribe(subscriber);
subscriber.assertNoErrors();
subscriber.assertSubscribed();
subscriber.assertComplete();
}
}
I would do the test like this:
public class DoStandardLoginUsecaseTest {
private DoStandardLoginUsecase target;
private MyApplication contextMock;
#Before
public void beforeEach() {
contextMock = Mockito.mock(MyApplication.class);
// Note that you need to mock the getPresenterComponent
// but I don't know what it returns.
target = new DoStandardLoginUsecase(contextMock);
}
#Test
public void buildUseCaseObservable() {
UserDataRepository userDataMock = Mockito.mock(UserDataRepository.class);
StandardLoginInfo loginInfoMock = Mockito.mock(StandardLoginInfo.class);
target.mUserDataRepo = userDataMock;
target.setLoginInfo(loginInfoMock);
Observable<Login> expected = // create your expected test data however you like...
Mockito.when(userDataMock.doStandardLogin(loginInfoMock)).thenReturn(expected);
Observable<Login> actual = target.buildUseCaseObservable();
Assert.areSame(actual, expected);
}
}

Export an object with Spring JMX annotations

I'm trying to export some information with Spring JMX annotation driven (I have no xml :D). I have achieved to export Strings and Integer types but I haven't been able to export any object of a class I created.
This is my #Configuration class.
#Configuration
#EnableMBeanExport
#ComponentScan({"my.packages"})
public class AppManager {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppManager.class);
context.refresh();
try {
TimeUnit.MINUTES.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Bean(name = "jmxExporter")
public Exporter jmxExporter() {
return new Exporter();
}
}
This is some class I have with some attributes I want to get.
public class MyClass implements Serializable {
private int param1;
private int param2;
private int param3;
public MyClass() {
// calculate all params
}
public int getParam1() {
return this.param1;
}
public int getParam2() {
return this.param2;
}
public int getParam3() {
return this.param3;
}
}
This is the class that exports it's attributes.
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
#ManagedResource(objectName = "my.packages:type=JMX,name=Exporter")
public class Exporter {
#ManagedAttribute
public String getString() { //This works!
return "Test string";
}
#ManagedAttribute
public MyClass getMyClass() { //This does not work
return new MyClass();
}
}
I need to create MyClass object every time because it has some real-time information that I can't export separately.
In JConsole the value of attribute is "Unavailable".
I'm pretty new to JMX and obviously missing something.
Thank you for your help!
I resolved it by returning CompositeData.
#ManagedAttribute
public CompositeData getMyClass() {
return createCompositeDataForMyClass();
}
I built a CompositeDataSupport for that and it worked.
return new CompositeDataSupport(compositeType, itemNames, itemValues);
Where compositeType is a CompositeType, itemNames is a String[] and itemValues is an Object[].
The CompositeType can be built with something like this
new CompositeType(typeName, typeDescription, itemNames, itemDescriptions, itemTypes);
typeName, typeDescription are Strings. itemNames and itemDescriptions are String[]. itemTypes is an OpenType[]. SimpleType and CompositeType can be used to build OpenType.
All this objects must be imported with
import javax.management.openmbean.*;

How can I a get singleton from Guice that's configured with runtime parameters?

My overall goal is to load properties from a properties file and then inject those properties into my objects. I would also like to use those properties to instantiate certain singleton classes using Guice. My singleton class looks like this:
public class MainStore(){
private String hostname;
#Inject
public void setHostname(#Named("hostname") String hostname){
this.hostname = hostname;
}
public MainStore(){
System.out.println(hostname);
}
}
I'm trying to instantiate a singleton using this provider:
public class MainStoreProvider implements Provider<MainStore> {
#Override
public MainStore get(){
MainStore mainStore = new MainStore();
return mainStore;
}
}
My configurationModule is a module that loads a configuration from a property file specified at runtime:
public class ConfigurationModule extends AbstractModule {
#Override
protected void configure(){
Properties properties = loadProperties();
Names.bindProperties(binder(), properties);
}
private static Properties loadProperties() {
String resourceFileName = "example.properties";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(resourceFileName);
Properties properties = new Properties();
properties.load(inputStream);
return properties;
}
}
And my example.properties files contains:
hostname = testHostName
Then when I need the MainStore singleton I'm using:
Injector injector = Guice.createInjector(new ConfigurationModule());
MainStoreProvider mainStoreProvider = injector.getInstance(MainStoreProvider.class);
MainStore mainStore = mainStoreProvider.get(); //MainClass singleton
Is this the right path to go down? Should I be doing this a completely different way? Why does my MainStore not print out the correct hostname?
I have written up a small example that demonstrates how to bind a Singleton, how to inject a property and so on.
public class TestModule extends AbstractModule {
#Override
protected void configure() {
Properties p = new Properties();
p.setProperty("my.test.string", "Some String"); // works with boolean, int, double ....
Names.bindProperties(binder(),p);
bind(X.class).to(Test.class).in(Singleton.class); // This is now a guice managed singleton
}
public interface X {
}
public static class Test implements X {
private String test;
#Inject
public Test(#Named("my.test.string") String test) {
this.test = test;
System.out.println(this.test);
}
public String getTest() {
return test;
}
}
public static void main(String[] args) {
Injector createInjector = Guice.createInjector(new TestModule());
Test instance = createInjector.getInstance(Test.class);
}
}
The configure method is now responsible to tell guice that my Test class is a singleton.
It prints the correct hostname (property test) because I inject the constructor and set the property.
You can do this with a provider as well, however you will then have to create your objects manually. In my case, this would look like this:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
public TestProvider(#Named("my.test.string") String test) {
this.test = test;
}
#Override
public X get() {
if(instance == null) {
instance = new Test(test);
}
return instance;
}
}
Binding will then look like this:
bind(X.class).toProvider(TestProvider.class);
Is this what you wanted?
Cheers,
Artur
Edit:
I did some test and found this to note:
You can bind a provider as a singleton:
bind(X.class).toProvider(TestProvider.class).in(Singleton.class);
That way you do not need to handle singleton creation yourself:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
#Inject
public TestProvider(#Named("my.test.string") String test) {
this.test = test;
}
#Override
public X get() {
return instance;
}
}
The above code will create singletons of the object X.

Categories