I am trying to write a unit test for a legacy code. The class which I'm testing has several static variables. My test case class has a few #Test methods. Hence all of them share the same state.
Is there way to reset all static variables between tests?
One solution I came up is to explicitly reset each field, e.g.:
field(MyUnit.class, "staticString").set(null, null);
((Map) field(MyUnit.class, "staticFinalHashMap").get(null)).clear();
As you see, each variable needs custom re-initialization. The approach is not easy to scale, there are a lot such classes in the legacy code base. Is there any way to reset everything at once? Maybe by reloading the class each time?
As a possible good solution I think is to use something like powermock and create a separate classloader for each test. But I don't see easy way to do it.
Ok, I think I figured it out. It is very simple.
It is possible to move #PrepareForTest powermock's annotation to the method level. In this case powermock creates classloader per method. So it does that I need.
Let's say I'm testing some code involving this class:
import java.math.BigInteger;
import java.util.HashSet;
public class MyClass {
static int someStaticField = 5;
static BigInteger anotherStaticField = BigInteger.ONE;
static HashSet<Integer> mutableStaticField = new HashSet<Integer>();
}
You can reset all of the static fields programmatically using Java's reflection capabilities. You will need to store all of the initial values before you begin the test, and then you'll need to reset those values before each test is run. JUnit has #BeforeClass and #Before annotations that work nicely for this. Here's a simple example:
import static org.junit.Assert.*;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Map;
import java.util.HashMap;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class MyTest extends Object {
static Class<?> staticClass = MyClass.class;
static Map<Field,Object> defaultFieldVals = new HashMap<Field,Object>();
static Object tryClone(Object v) throws Exception {
if (v instanceof Cloneable) {
return v.getClass().getMethod("clone").invoke(v);
}
return v;
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
Field[] allFields = staticClass.getDeclaredFields();
try {
for (Field field : allFields) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
Object value = tryClone(field.get(null));
defaultFieldVals.put(field, value);
}
}
}
catch (IllegalAccessException e) {
System.err.println(e);
System.exit(1);
}
}
#AfterClass
public static void tearDownAfterClass() {
defaultFieldVals = null;
}
#Before
public void setUp() throws Exception {
// Reset all static fields
for (Map.Entry<Field, Object> entry : defaultFieldVals.entrySet()) {
Field field = entry.getKey();
Object value = entry.getValue();
Class<?> type = field.getType();
// Primitive types
if (type == Integer.TYPE) {
field.setInt(null, (Integer) value);
}
// ... all other primitive types need to be handled similarly
// All object types
else {
field.set(null, tryClone(value));
}
}
}
private void testBody() {
assertTrue(MyClass.someStaticField == 5);
assertTrue(MyClass.anotherStaticField == BigInteger.ONE);
assertTrue(MyClass.mutableStaticField.isEmpty());
MyClass.someStaticField++;
MyClass.anotherStaticField = BigInteger.TEN;
MyClass.mutableStaticField.add(1);
assertTrue(MyClass.someStaticField == 6);
assertTrue(MyClass.anotherStaticField.equals(BigInteger.TEN));
assertTrue(MyClass.mutableStaticField.contains(1));
}
#Test
public void test1() {
testBody();
}
#Test
public void test2() {
testBody();
}
}
As I noted in the comments in setUp(), you'll need to handle the rest of the primitive types with similar code for that to handle ints. All of the wrapper classes have a TYPE field (e.g. Double.TYPE and Character.TYPE) which you can check just like Integer.TYPE. If the field's type isn't one of the primitive types (including primitive arrays) then it's an Object and can be handled as a generic Object.
The code might need to be tweaked to handle final, private, and protected fields, but you should be able to figure how to do that from the documentation.
Good luck with your legacy code!
Edit:
I forgot to mention, if the initial value stored in one of the static fields is mutated then simply caching it and restoring it won't do the trick since it will just re-assign the mutated object. I'm also assuming that you'll be able to expand on this code to work with an array of static classes rather than a single class.
Edit:
I've added a check for Cloneable objects to handle cases like the HashMap in your example. Obviously it's not perfect, but hopefully this will cover most of the cases you'll run in to. Hopefully there are few enough edge cases that it won't be too big of a pain to reset them by hand (i.e. add the reset code to the setUp() method).
Here's my two cents
1. Extract static reference into getters / setters
This works when you are able to create a subclass of it.
public class LegacyCode {
private static Map<String, Object> something = new HashMap<String, Object>();
public void doSomethingWithMap() {
Object a = something.get("Object")
...
// do something with a
...
something.put("Object", a);
}
}
change into
public class LegacyCode {
private static Map<String, Object> something = new HashMap<String, Object>();
public void doSomethingWithMap() {
Object a = getFromMap("Object");
...
// do something with a
...
setMap("Object", a);
}
protected Object getFromMap(String key) {
return something.get(key);
}
protected void setMap(String key, Object value) {
seomthing.put(key, value);
}
}
then you can get rid of dependency by subclass it.
public class TestableLegacyCode extends LegacyCode {
private Map<String, Object> map = new HashMap<String, Object>();
protected Object getFromMap(String key) {
return map.get(key);
}
protected void setMap(String key, Object value) {
map.put(key, value);
}
}
2. Introduce static setter
This one should be pretty obvious.
public class LegacyCode {
private static Map<String, Object> something = new HashMap<String, Object>();
public static setSomethingForTesting(Map<String, Object> somethingForTest) {
something = somethingForTest;
}
....
}
Both ways are not pretty, but we can always come back later once we have tests.
Related
I am trying to build a parameterized Junit Test in order to test each occurrence of a LinkedHashMap within an ArrayList of LinkedHashMaps. This is because each LinkedHashMap represents a test case.
The map is built/stored by a object within my TestSuite class, which utilizes the #BeforeClass annotation, as per below:
#RunWith(Suite.class)
public class TestSuite {
public static MapBuilder mapBuilder = new MapBuilder ();
#ClassRule
public static ExternalResource testResource = new ExternalResource();
#Override
protected void before () throws IOException {
mapBuilder.buildMap();
}
}
The .buildMap() method of Mapbuilder is expensive, so I do not wish to build it for every Junit Test, hence the need for parameterized class, as per below :
#RunWith(Parameterized.class)
public class TestCasesA {
private LinkedHashMap<Integer, Integer> currentMap;
public TestCasesA (LinkedHashMap<Integer, Integer> currentMap) {
this.currentMap = currentMap;
}
#Parameters
public static Collection<Object[]> dataFeed () {
Object[] objArray = TestSuite.MapBuilder.returnBuiltMap().toArray();
return Arrays.asList(new Object[][] {objArray});
}
#Test
// Some test which uses currentMap
}
However, when i run this i keep facing the below issue:
java.lang.IllegalArgumentException: wrong number of arguments at java.lang.reflect.Constructor.newInstance(Unknown Source)
I've been scouring Stack Overflow and other sites about this all day, but i still cannot work it out.
Not sure if this matters or not but my LinkedHashMap may contain between 1 upto around 32 key/value entries (Could contain more, but very unlikely).
I'v followed the plentiful examples online where you manually type what you want to return, and this works fine, but manually typing in is not suitable for what i'm trying to achieve.
I've even done a enhanced for loop within TestCasesB, called the .returnBuiltMap() method and printed out each iteration of the map just to prove my Test Cases can "see" the built map.
Can anyone help?
For reference, I am using Java 7 and Junit 4.
I've been researching this further myself due to lack of any answers (Uploading the wrong code in my original post was a bad move on my part admittedly).
I finally found the answer today - #BeforeClass runs after #Parameters, as discussed in great detail here > https://github.com/junit-team/junit4/issues/527
My above code was always going fail as my data set-up was performed after #Parameters ran, so #Parameters had nothing to feed into the designated constructor.
It seems you have forgotten to add the constructor, something like:
#RunWith(Parameterized.class)
public class TestCasesA {
private Integer paramA, paramB;
#Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 1, 1 },
{ 2, 2 }
});
}
public TestCasesA (Integer paramA, Integer paramB){
this.paramA = paramA;
this.paramB = paramB;
}
#Test
public void testYourParams() {
assertEquals(paramA, paramB);
}
}
I was also fasing this error:
java.lang.IllegalArgumentException: wrong number of arguments
after I removed paramether from constructor, but then I found that I also must delete it from #Parameterized.Parameters in
companior object. See the code below:
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
#ExperimentalCoroutinesApi
#RunWith(Parameterized::class)
class MyAppClass1UseCaseTest(
private val expectedFirstParam: String,
expectedSecondParam: Boolean //If you remove paramether from here, then you also have to remove param from copmanion // object below
) {
#Test
fun useCaseTest1() = runBlockingTest {
}
companion object {
#JvmStatic
#Parameterized.Parameters(name = "firstParam {0}, secondParam {1}") //you also need to remove param from here
fun data(): Collection<Array<Any?>> {
return listOf(
arrayOf("stringValue1", true), //and remove param from here
arrayOf("stringValue1", false)
)
}
}
}
In my framework I have a class like this:
public class Foo<B, V> {
private final Method getterMethod;
...
public V executeGetter(B bean) {
try {
return getterMethod.invoke(bean);
} catch ...
}
}
This class is used to call getters of classes created by users that aren't available at compile time of my framework. For example, B might be a class called Person.
Through profiling, I've discovered that this method is horribly slow. The Method.invoke() takes 40% of performance in sampling profiling (even with setAccessible(true)), while a non reflective implementation takes only a small fraction of that performance.
So I 'd like to replace is with a MethodHandle:
public class Foo<B, V> {
private final MethodHandle getterMethodHandle;
...
public V executeGetter(B bean) {
try {
return getterMethodHandle.invoke(bean);
} catch ...
}
}
But then I get this exception:
java.lang.ClassCastException: Cannot cast [Ljava.lang.Object; to Person
at sun.invoke.util.ValueConversions.newClassCastException(ValueConversions.java:461)
at sun.invoke.util.ValueConversions.castReference(ValueConversions.java:456)
at ...Foo.executeGetter(Foo.java:123)
even though bean is an instance of Person. Now the misleading part is that it's trying to cast an Object[] (and not an Object) to Person. Note that wrapping it in an object array (which is a performance loss) doesn't help:
return getterMethodHandle.invoke(new Object[]{bean}); // Same exception
Is it possible to get the MethodHandle to work in this situation?
That ClassCastException only occurs if you compile with source/target level java 6.
Compile with source/target level 7 or higher to avoid that ClassCastException.
Answer found thanks to Tagir's answer. (vote up his answer too)
Using MethodHandles in framework/library code is perfectly fine and I see no problem in your code. This example works just fine:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class Foo<B, V> {
private final MethodHandle getterMethodHandle;
public Foo(MethodHandle mh) {
this.getterMethodHandle = mh;
}
public V executeGetter(B bean) {
try {
return (V) getterMethodHandle.invoke(bean);
} catch(RuntimeException | Error ex) {
throw ex;
} catch(Throwable t) {
throw new RuntimeException(t);
}
}
static class Pojo {
String x;
public Pojo(String x) {
this.x = x;
}
public String getX() {
return x;
}
}
public static void main(String[] args) throws Exception {
// I prefer explicit use of findXYZ
Foo<Pojo, String> foo = new Foo<>(MethodHandles.lookup()
.findVirtual(Pojo.class, "getX", MethodType.methodType(String.class)));
// Though unreflect also works fine
Foo<Pojo, String> foo2 = new Foo<>(MethodHandles.lookup()
.unreflect(Pojo.class.getMethod("getX")));
System.out.println(foo.executeGetter(new Pojo("foo")));
System.out.println(foo2.executeGetter(new Pojo("bar")));
}
}
The output is:
foo
bar
For even better performance consider using invokeExact, though it will not allow you automatic type conversions like unboxing.
Class I want to test:
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
public class Subject {
private CacheLoader<String, String> cacheLoader = new CacheLoader<String, String>() {
#Override
public String load(String key)
throws Exception {
return retrieveValue(key);
}
};
private LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.build(cacheLoader);
public String getValue(String key) {
return cache.getUnchecked(key);
}
String retrieveValue(String key) {
System.out.println("I should not be called!");
return "bad";
}
}
Here's my test case
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class SubjectTest {
String good = "good";
#Spy
#InjectMocks
private Subject subject;
#Test
public void test() {
doReturn(good).when(subject).retrieveValue(anyString());
assertEquals(good, subject.getValue("a"));
}
}
I got
org.junit.ComparisonFailure:
Expected :good
Actual :bad
This comes down to the implementation of the spy. According to the docs, the Spy is created as a copy of the real instance:
Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it. So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their effect on real instance state. The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any effects on the real instance.
It seems to be a shallow copy. As a result, as far as my debugging shows, the CacheLoader is shared between the copy and the original object, but its reference to its enclosing object is the original object, not the spy. Therefore the real retrieveValue is called instead of the mocked one.
I'm not sure offhand what the best way to resolve this would be. One way for this specific example would be to invert the CacheLoader dependency (i.e. pass it into Subject instead of Subject defining it internally), and mock that instead of Subject.
Mark Peters did a great job diagnosing and explaining the root cause. I can think of a couple workarounds:
Move cache (re)initialization into a separate method.
By calling new CacheLoader from within the spy, the anonymous inner class is created with a reference to the spy as the parent instance. Depending on your actual system under test, you may also benefit from getting the cache creation out of the constructor path, especially if there's any heavy initialization or loading involved.
public class Subject {
public Subject() {
initializeCache();
}
private LoadingCache<String, String> cache;
#VisibleForTesting
void initializeCache() {
cache = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
#Override
public String load(String key) throws Exception {
return retrieveValue(key);
}
});
}
/* ... */
}
#Test
public void test() {
subject.initializeCache();
doReturn(good).when(subject).retrieveValue(anyString());
assertEquals(good, subject.getValue("a"));
}
Make a manual override.
The root cause of your trouble is that the spy instance is different from the original instance. By overriding a single instance in your test, you can change behavior without dealing with the mismatch.
#Test
public void test() {
Subject subject = new Subject() {
#Override public String getValue() { return "good"; }
}
}
Refactor.
Though you can go for full DI, you may be able to just add a testing seam to the value function:
public class Subject {
private CacheLoader<String, String> cacheLoader = new CacheLoader<String, String>() {
#Override
public String load(String key) throws Exception {
return valueRetriever.apply(key);
}
};
private LoadingCache<String, String> cache =
CacheBuilder.newBuilder().build(cacheLoader);
Function<String, String> valueRetriever = new Function<String, String>() {
#Override
public String apply(String t) {
System.out.println("I should not be called!");
return "bad";
}
};
public String getValue(String key) {
return cache.getUnchecked(key);
}
}
#Test
public void test() {
subject = new Subject();
subject.valueRetriever = (x -> good);
assertEquals(good, subject.getValue("a"));
}
Naturally, depending on your needs, valueRetriever could be an entirely separate class, or you could accept an entire CacheLoader as a parameter.
I had same issue, for Mockito 1.9.5 possible solution may be to change method visibility to "protected". Honestly, I have no idea how it works, but still, error gone.
I am working on a project in java and am quite new to the language and OOP. My dilema is that I want to carry out a task/function from a specific class based on the value of a variable.
This is kind of what I am trying to achieve.
class mainClass{
String option;
public static void main(String[] args) {
mainClass main = new mainClass();
}
mainClass(){
secondClass sC = new secondClass();
thirdClass tC = new thirdClass();
switch (option){
case "1" :
sC.doSomething();
case "2" :
tC.doSomething();
}
}
}
class secondClass{
void doSomething(){
System.out.println("1");
}
}
class thirdClass{
void doSomething(){
System.out.println("2");
}
}
The reason I don't want to do this, is because if I want to add a fourth, fifth, sixth class etc... I would have to update the switch.
I tried using a hashmap. Where I assigned secondClass the key of "1". But then I would have to cast the object, but this brings me back to the original headache of not knowing what class would need to be called in advance.
So then I tried using a hashmap like this,
HashMap<String, Object> map = new HashMap<String, Object>();
Which I could then do map.get("1") but then now I can't call any of the methods for the class in question.
If I need to use a large switch statement I will, but I am actively seeking a more efficient alternative.
You were right to use a Map but you were also right to balk at casting. However, nowadays with generics you can get around all that:
interface DoesSomething {
// An object implementing this interface does something.
public void doSomething();
}
// Class that does something.
class FirstClass implements DoesSomething {
#Override
public void doSomething() {
// What FirstClass does.
}
}
// Another class that does something.
class SecondClass implements DoesSomething {
#Override
public void doSomething() {
// What SecondClass does.
}
}
// How I know what to do. Map the string to a DoesSomethng.
Map<String, DoesSomething> whatToDo = new HashMap<>();
{
// Populate my map.
whatToDo.put("1", new FirstClass());
whatToDo.put("2", new SecondClass());
}
public void doSomethingDependingOnSomething(String something) {
// Look up the string in the map.
DoesSomething toDo = whatToDo.get(something);
// Was it in there?
if (toDo != null) {
// Yes! Make it do it's thing.
toDo.doSomething();
}
}
If you want to avoid using Reflection (wich is discouraged here), you should consider a simple SAM-Interface:
public interface Doable { public void doSomething(); }
and have all classes implement the interface (no other changes required in these classes) and having a Map<String, Doable> and calling
if (map.containsKey(option)) map.get(option).doSomething();
// Or (may be a little faster)
Doable opt = map.get(option);
if (opt != null) opt.doSomething();
If your implementations have different methods, you'll most likely be bound to use Reflection to get the declared methods and compare by String.
I make singleton class and use this class object in different class this code work fine in eclipse
but when i make runnable jar than it take empty hashmap list i don't know why my code...
My singleton class
public class PointCalculate {
public HashMap<String, Float> calPoint;
private static PointCalculate instance;
private PointCalculate(){
calPoint = new HashMap<String, Float>();
}
public static PointCalculate getInstance(){
if(instance==null){
instance = new PointCalculate();
}
return instance;
}
public void calculatePoint(String uid ,float point){
Float ps = instance.calPoint.get(uid);
if(ps==null) {
ps = point;
instance.calPoint.put(uid, ps);
}
else {
ps = point+ps.floatValue();
instance.calPoint.put(uid, ps);
}
}
}
and i am passing value from this class below....
public class Exp {
public void setpoint(){
PointCalculate obj = PointCalculate.getInstance();
obj.calculatePoint(rowkey, point);//rowkey and point come from file.....
}
}
now i am passing hashmap....
public static void main(String args[]) throws Exception {
PointCalculate obj = PointCalculate.getInstance();
SqlInsertPoint.givePoint(obj.calPoint);
}
but in SqlInsertPoint.givePoint() hashmap list will be empty i don't know why if any body know than help me
Thanks in advance
What is wrong with this code? In main you obtain an instance of PointCalculate, do not put any points into it, and pass it over to givePoint method. Since you didn't populate the HashMap, it should be empty.
On a separate note, static Singletons are difficult to get right, and in general should be avoided (couple good reasons). In your concrete case not only PointCalculate class is not thread-safe, but it also exposes calPoint to the whole world. So, anybody can run the following code and essentially override your instance.
PointCalculate.getInstance().calPoint = new HashMap();