我需要访问私有地图进行单元测试,但无法执行此操作。
主要课程:
public class TestMe{
private Map<String, SomeObject> testMap = new HashMap<String, SomeObject>();
}
单元测试:
public class TestMeTester{
public testTestMe(){
TestMe obj = new TestMe();
Class clazz = obj.getClass();
Field field = clazz.getDeclaredField("testMap");
field.setAccessible(true);
Map<String, SomeObject> refMap = (HashMap<String, SomeObject>) field.get(new HashMap<String, Object>());
System.out.println("==>" + refMap);
}
}
例外:
java.lang.IllegalArgumentException: Can not set java.util.Map field com.xx.TestMe.testMap to java.util.HashMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
答案 0 :(得分:3)
您必须使用Field.get()
对象调用TestMe
。
TestMe obj = new TestMe();
....
Map<String, SomeObject> refMap = (HashMap<String, SomeObject>) = field.get(obj);
您的代码会在Field.get()
的新实例上调用HashMap
。
field.get(new HashMap<String, Object>()); // This will not work in your case
编辑评论:这不起作用。
我试图弄明白什么不行。这是我的测试代码,它可以工作。
public class TestMeTester {
public static class TestMe {
private Map<String, String> testMap = new HashMap<String, String>();
}
public static void main(String[] args) throws IllegalArgumentException,
IllegalAccessException, SecurityException, NoSuchFieldException {
TestMe obj = new TestMe();
Class clazz = obj.getClass();
Field field = clazz.getDeclaredField("testMap");
field.setAccessible(true);
Map<String, String> refMap = (HashMap<String, String>) field.get(obj);
System.out.println("==>" + refMap);
}
}
答案 1 :(得分:0)
如果您需要访问地图进行单元测试,请添加默认访问getter方法。编写代码以支持单元测试没有错:
Map<String, SomeObject> getTestMap() {...}
反射应该是您的最后选择,通常是在您没有机会编辑目标类时。
答案 2 :(得分:0)
我认为你应该这样做
Map<String, SomeObject> refMap = (HashMap<String, SomeObject>) field.get(obj);
如以下(工作)代码所示:
import java.lang.reflect.Field;
public class Test {
static public void main(String[] args) throws Exception {
Foo f = new Foo();
Field x = f.getClass().getDeclaredField("x");
x.setAccessible(true);
System.out.println("Before: " + x.get(f)); // prints 1
x.set(f, (Integer)2);
System.out.println("After: " + x.get(f)); // prints 2
}
}
class Foo {
private Integer x = 1;
}
否则,您正在尝试检索testMap
的{{1}}字段,该字段不存在。
除了您通过反射访问私有字段的问题之外,编写依赖于这些实现细节(即私有字段的存在)的单元测试很可能很快就会破解。我建议看一下以下链接:
http://xunitpatterns.com/Fragile%20Test.html#Overcoupled%20Software http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Use%20the%20Front%20Door%20First
答案 3 :(得分:0)
所以我只是通过我的代码的一些试验和错误来解决它:
如果你像我一样,你必须使用Java Reflection,那么请继续阅读,否则,@ Duncan已经提到了一种有效的方法,只需制作一个方法来获取HashMap用于测试目的。
现在,你要做的是:
声明类型字段作为您对私有地图的引用,并初始化包含
的类
private Map: Field map = ClassName.class.getDeclaredField(String "name of map")
将您的Field实例设置为可访问:map.setAccessible(true)
由于您知道Field是Map,因此您可以将Object转换为Map,然后在Field pass参数上调用Map方法。
Field instance.get(obj) call. (Map) map.get(classNameInstance)
在测试中我得到一个错误,说明我的情况下的assertEquals(Object,Object)。为了避免这个问题,我简单地将它转换为原语。我也检查了它也适用于String,所以它应该适用于所有其他定义的对象。
这是一个编码示例供参考。在我的情况下,我不得不使用将字符串映射到整数的HashMap,我最后的转换错误是我无法使用assertEquals比较int和Integer,所以我将Integer转换为int:
public class KeywordCollection{
private static HashMap<String, Integer> map = new HashMap<String, Integer>();
//Etc. for KeywordCollection, only the private initialization is relevant
}
public void addTests() throws SecurityException, NoSuchFieldException,
Exception, IllegalAccessException {
KeywordCollection keys1 = new KeywordCollection();
Field map = KeywordCollection.class.getDeclaredField("keywordTable");
map.setAccessible(true);
// Test if add works trivially
assertTrue(keys1.addKeyword("First"));
assertFalse(keys1.addKeyword("First"));
assertFalse(keys1.addKeyword("FIrST"));
assertTrue(keys1.addKeyword("Inductive"));
assertTrue(keys1.addKeyword("Not in keys2"));
System.out.println(map.get(keys1).toString());
output: {Not in keys2=3, Inductive=2, First=1}
//For getting values
assertEquals(1,(int) ((HashMap<String, Integer>) map.get(keys1)).get("First"));
所以你可以看到使用强制调用(HashMap<String, Integer>) map.get(keys1)
我设置Field map实例来引用我的对象类KeywordCollection,它有我的HashMap,然后将它从Object转换为HashMap,这样我就可以访问我的HashMap方法了。否则它只访问Object方法。使用它,您可以像往常一样在地图上运行测试(访问map.keySet,contains,get(key)等等。)
另外,不要担心所有例外情况。我在Eclipse中进行编码,因此它给出了未处理异常的警告,所以我设置为抛出根据API的方法抛出的异常。如果你很好奇它们属于Field变量,但如果你知道你所调用的方法中你的字段是什么,那么使用这种方法就不会有问题。
NoSuchFieldException表示您在您调用的类中传递的名称没有变量
和IllegalAccessException意味着您无权访问该字段(即您未将setAccessible设置为true)
另外不要忘记你的进口。对于Field,您导入java.lang.reflect.Field(我喜欢使用*)
希望它有所帮助。