在没有getter和setter方法的情况下模拟/存根类的私有变量

时间:2016-08-23 06:41:22

标签: java mockito powermockito

我最近开始研究TDD for exisitng项目并面临几个问题,其中一个问题如下所述

我有一个私有变量要在测试类中进行模拟,变量如下所示

private Class<XYZ> cls = XYZ.class;

以后这个“cls”变量用作className

之一的方法的arugment
private List create(Class className, Object objectTO,   List<String> names)

我知道私有变量可以被嘲笑 我通过以下步骤

在我的测试用例中模拟了私有变量
  1. 声明了java.lang.reflect.Field;
  2. Field field = PowerMockito.field(XYZ.class,"cls");
  3. field.set(XYZ.class, "objectOfXYZClass");
  4. 当我运行我的测试课时,我遇到了错误

    java.lang.IllegalArgumentException: Can not set java.lang.Class field com.tools.XYZ.cls to java.lang.Class
    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.set(UnsafeObjectFieldAccessorImpl.java:75)
    at java.lang.reflect.Field.set(Field.java:680)
    

    请有人帮我解决这个问题,让我知道我错过了什么。

    PS:我使用@preparefortest并提及了所有必需的类,并使用@runwith(powermockrunner.class)运行我的测试类

2 个答案:

答案 0 :(得分:2)

您的单元测试错误。它们不是测试内部实现(如字段或私有方法)。

单元测试通常只应执行以下操作:

  1. 您创建了“被测试的课程”的对象
  2. 您在该对象上调用公开方法;并且你将结果“断言”给那些调用(例如,包括在这里或那里预期某些例外)。
  3. 换句话说:您非常希望仅测试“被测试类”的外部可见行为。而且你知道:如果你的班级没有外部可见的行为 - 为什么你有这个行为呢?!

    当然,有时这不是“足够好”。在这种情况下,你通常会做什么:你转向一些模拟框架(如EasyMock或Mockito)来创建模拟的对象。在实例化测试中的类(称为依赖注入)时,可以使用这些模拟。通过这样做,您可以完全控制您所测试的课程;例如,您可以验证您的模拟是否会看到您期望的那些方法调用。

    所以,长话短说:是的,有可能以某种方式访问​​正在测试的类的字段。但这导致了不值得这个名字的单元测试。因为一旦您开始重构代码的内部,这些测试就会中断。从这个意义上讲:这样的测试只能证明您当前的实现按预期工作。但是每当你改变某些东西时,你将不得不返工(可能更大!)零件或你的测试代码。

    最后:编写单元测试是一项需要学习的技能。达到目标的最佳资源之一是videos

答案 1 :(得分:1)

new Thread(new Runnable() {
                @Override
                public void run() {
///background calculations
try {
                            Thread.sleep(1000L);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

runOnUiThread(new Runnable() {
            @Override
            public void run() {
//main thread task to update user interface
            }
        });
}
}).start();

放入集合,类的实例。不上课。因为您将字符串“objectOfXYZClass”设置为对象。不进入班级;) 我要添加

field.set(instanceOfClassXYZ, "")