I have a static class that I would like to refactor so I can change the name of the properties file etc., and to be able to unit test it easier.
Current I have this:
public enum MySettings {
INSTANCE;
//priv vars
private string applicationUrl;
private MySettings() {
MappingJsonFactory jf = new MappingJsonFactory();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream mySettingsInputStream = classLoader.getResourceAsStream("a.properties");
Properties mySettingsProperties = new Properties().load(mySettingsInputStream);
// code below to load json and set priv vars etc.
}
public String getApplicationUrl() {
return applicationUrl;
}
}
How could I set the name of the properties file to something else in my unit tests?
"Inversion of control." The simplest way to do this here would be to take it in as a constructor arg. At the higher end would be an IOC framework, such as Spring.
Worse case since you're dealing with an enum - may need to factor out an interface then provide an implementing enum. Or better:
public enum Settings {
PRODUCTION("prod.xml"), UNIT_TESTING("dev.xml");
//...
you could fiddle all the stuff from the enum class into a real instantiable class (via package protection or protected) and then make an instance of it accessible via the enum (getter). Like this you can unit test everything like a charm and also have it as a singleton :). With this you don't need a second Enum constant (as pointed out in the comments).
If you are using protected instead of package protection you can unit test it by creating a dummy class that inherits from the actual class and instantiate it in the test like this:
private static class Dummy extends NewClass {
public Dummy() {
super();
}
}
Related
I have an application class "Application", one abstract class "AbstractClass" extended by "Impl1" and "Impl2".
The application class gets the impl1 or impl2 to perform some task based on the input it receives.
Currently I am injecting both the classes into the application class as shown below.
Then based on input, I either ask impl1 OR impl2 to perform the task.
public class Application {
private static final Data data1 = DATA_CONFIG.data_1;
private final AbstractClass impl1;
private final AbstractClass impl2;
#Inject
Application(final AbstractClass impl1, final AbstractClass impl2){
this.impl1 = impl1;
this.impl2 = impl2;
}
public void mainTask(final Data data){
if(data == data1){
impl1.performTask();
}else{
impl2.performTask();
}
}
}
But, is there any way I could use assisted inject or a similar concept to inject only the dependency required, so for example input is data1, I only inject impl1 and not impl2.??
So, what you want is to select injected object depending to some context of injection point - value of Data object in particular. I didn't do such things and can't guarantee success, but you can try custom injections.
Also you can do something like factory. But IMHO, this approach is not much better than original, cause it will just move selection between impl1 and impl2 to a factory class you have to create first.
Sketch:
#Inject
Application(IAbstractClassFactory factory){
this.factory = factory
}
void mainTask(final Data data){
impl = factory.create(data)
}
public class OneClass {
private AnotherClass anotherClass = new AnotherClass();
private void doOneJob(){
anotherClass.doOtherJob();
}
}
In the above code, AnotherClass is instantiated and held as a class variable of OneClass.
What are the consequences of this design?
Is it a good practice?
Will this support unit testing?
This is called composition and is a fundamental part of Java language. There is nothing wrong with it, and might be essential in a lot of cases.
The only change I would do is use dependency injection to make it easier for testing, i.e. you'll be able to supply a mock AnotherClass object this way:-
public class OneClass {
private AnotherClass anotherClass;
public OneClass(AnotherClass anotherClass){
this.anotherClass = anotherClass;
}
private void doOneJob() {
anotherClass.doOtherJob();
}
}
It is hard to "unit" testing because you cant mock the "external" dependency in a normal way. (With groovy tests for example you can override private fields with a mock)
I think it would be better that you have a constructor that accepts a AnotherClass than you can mock it in a unit test via constructor.
I have a enum that has to have a inner static class for bean injection.
I feel I'm facing the most difficult situation for a mock: enum, static class, static field, static method..
public enum Category{
C1(Something(Constants.getFactory().createSomething(""))),
C2(...);
public static Constants {
#Autowired
private static Factory factory;
public static Factory getFactory(){
return factory;
}
}
}
And my testing class using PowerMockito is:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Category.class,Category.Constants.class})
public class CategoryTests {
#Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Category.class);
PowerMockito.mockStatic(Category.Constants.class);
//This simply testing mock didn't work
//PowerMockito.when(Category.Constants
// .getFactory()).thenReturn("123");
//I tried to mock the inner field 'factory' and use it directly without a getter
//(with small changes in the original class)
//But it didn't work either
Factory factory = PowerMockito.mock(Factory.class);
NewClass newClass = PowerMockito.mock(NewClass.class);
PowerMockito.when(Factory.createSomething(anySring()))
.thenReturn(newClass);
Whitebox.setInternalState(
Category.Constants.class,"factory",Factory);
//This is like the most common way to stub
//It didn't work, so I believe the inner static class were never mocked
PowerMockito.doReturn(factory).when(Category.Constants.class,
"getFactory", anyString());
}
//I don't know if real test cases matter that much but I update to add it for reference.
#Test(dataProvider = "Case1")
public void testFromFilterType(final String testName, String input, final Category expected) {
assertEquals(Category.doSomething(input), expected);
}
#DataProvider(name = "Case1")
Object[][] fromFilterTypeCases() {
return new Object[][] {
{ "C1", "input1", Category.C1 },
{ "C2", "input2", Category.C2 },
};
}
}
//Currently the tests got skipped because in class Category Constants.getFactory().createSomething(""),
//where Constants.getFactory() returns null and mocking doesn't work.
At first I didn't mock the Enum, but just the static inner class. After heavily searching, I tried in all ways. The setup seems correct but it may miss some tricks. Any helps?
A bit of guessing: Category.class is the class you intend to test. That class itself contains nothing that should require mocking/preparation.
So: drop these parts in your code. Even if it doesn't cause your current issue, I am pretty sure that it might have all kinds of unwanted consequences when you start testing things later on.
Beyond that, the real answer would be to avoid the necessity for PowerMock(ito) in the very first place. You are already using #Autowired, which implies that you are using a DI framework. Most DI frameworks also have hooks for unit testing. So you should rather try to get #Autowired to work in your test setup.
I'm trying to mock the following class which contains some static members
public class ClientFact {
private static final String BASE_URL = Config.getProperty("prop1");
private static final String USERID = Config.getProperty("prop2");
......................
public static Client createClient() throws AppException {
}
}
but i'm running into issues with the static member variables which are populated by Config.getProperty. This class does a read on a properties file like so
public class Config {
...............
public static String getProperty(Param param) {
String value = null;
if (param != null) {
value = properties.getProperty(param.toString());
}
return value;
}
}
I'm trying to mock this call since i dont care about the loaded properties in my test. This is what ive tried
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClientFact.class})
public class MyTests {
#Test
public void test() {
PowerMock.mockStaticPartial(Config.class, "getProperty");
EasyMock.expect(Config.getProperty(EasyMock.anyObject())).andReturn(EasyMock.anyString()).anyTimes();
PowerMock.mockStatic(ClientFact.class);
}
}
but its giving the following error...
java.lang.NoSuchMethodError: org/easymock/internal/MocksControl.createMock(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Ljava/lang/Object;
at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2214)
at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
any ideas what im doign wrong here?
A non-answer: consider not making static calls there.
You see, that directly couples that one class to the implementation of that static method in some other class; for no real reason. (and for the record: it seems strange that a USER_ID String is a static field in your ClientFact class. Do you really intend that all ClientFacts are using the same USER_ID?!)
You could replace that static call with a non-static version (for example by introducing an interface); and then you can use dependency injection to make an instance of that interface available to your class under test. And then all your testing works without the need to Powermock.
Long story short: very often (but not always!) the need to turn to Powermock originates in production code which wasn't written to be testable (like in your case). Thus instead of using the big bad Powermock hammer to "fix" your testing problem, you should consider improving your production code.
You might want to listen to those videos to get a better understanding what I am talking about.
I have example to ilustrate my problem:
package com.example;
public class ExamplePublicClass {
public void doSomething() {
// a lot of code
String message = new ExamplePublicClass.MessageBuilder().withName("someName").build();
// a lot of code
}
private static class MessageBuilder {
private String name;
public MessageBuilder withName(String name) {
this.name = name;
return this;
}
public String build() {
return this.name + 1;
}
}
}
doSomething() method doing a lot o things and there is a lot o legacy code but it works and I don't want to touch her.
Only what I want to do is a change a builder to creating a log message and write a test for him. The problem is the fact that MessageBuilder is a private class and is doesn't make sense to change it to public.In additonal I don't want to changing visibility through reflection.
I added a class for test in the same package
package com.example;
import org.junit.Test;
public class MessageBuilderTest {
#Test
public void testMessageBuilder() {
String s = MessageBuilder..
}
}
but I don't have access to this private class :(
Working code is located in
src/main/java
and test code is located
src/test/java
What do you thing? Should I change project structure to
src
|/main/java
|/test/java
?
Or exist better solution?
Best Regards
T
I've always considered modifying access via Reflection as a bad practice, which is useful for nothing but understanding that there is something wrong with the design. :-)
In general, a unit test is intended to test the public (or actually, the non-private) interface of a class. All private methods are implementation detail that you would not expect to test explicitly.
When you have private methods in a class and you want to Unit-test them, this is considered as a sign for a code smell, because the class can be simplified/modified so that the private units are unit-testable.
You can do one of these:
refactor the nested private static class to a top-level one and mark it as package-private accessible.
provide a public (or, at least, non-private) access to the private units that you want to test.
You can also take a look on this thread, where the topic is discussed more extensively.