【问题标题】:How to test private member objects without making a new object如何在不创建新对象的情况下测试私有成员对象
【发布时间】:2019-08-12 17:21:01
【问题描述】:

我正在尝试针对一个类编写单元测试。我无法更改课程,但我认为可以使用反射进行测试。我只是不知道该怎么做。这是课程:

public class MyClass extends AnotherClass implements TheInterface
{
    private enum SomeTypes
    {
        SAMPLE01, SAMPLE02, SAMPLE03
    }

    private CircularList<SomeTypes> someTypesList; 
    Date date= new Date();
    private SomeOtherClassProcessor01 someOtherClassProcessor01;
    private SomeOtherClassProcessor02 someOtherClassProcessor02;
    private SomeOtherClassProcessor03 someOtherClassProcessor03;

    public Properties initialize (Properties properties) throws Exception
    {
        Properties propertiesToReturn = super.initialize(properties);
        someTypesList = new CircularList<SomeTypes>    (Arrays.asList(SomeTypes.values())); 
        someOtherClassProcessor01 = new SomeOtherClassProcessor01(); 
        someOtherClassProcessor02 = new SomeOtherClassProcessor02(); 
        someOtherClassProcessor03 = new SomeOtherClassProcessor03(); 

        return propertiesToReturn;
    }

    @Override
    public void get(ImportedClass someParams) throws Exception
    {
        SomeTypes types = someTypesList.getFirstAndRotate();

        switch(types)
        {
            case SAMPLE01:
            someOtherClassProcessor01.doSomething(someParams,     date);
            break;
            case SAMPLE02:
            someOtherClassProcessor02.doSomething(someParams,     date);
            break;
            case SAMPLE03:
            someOtherClassProcessor03.doSomething(someParams,     date);
            break;
            default:
            throw new IllegalArgumentException("This " + types + "     was not implemented.");
        }
    }   
}

对于我的测试,这是我目前所做的......不确定如何实际做到这一点。

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class TestingMyClass
{
    MyClass mockMyClass;
    SomeOtherClassProcessor01 someOtherClassProcessor01;
    SomeOtherClassProcessor02 someOtherClassProcessor02;
    SomeOtherClassProcessor03 someOtherClassProcessor03;
    Date date;


    @Before
    public void initialize () throws Exception
    {
        mockMyClass = spy(new MyClass()); 
        mockSomeOtherClassProcessor01 =     mock(SomeOtherClassProcessor01.class);
        mockSomeOtherClassProcessor02 =     mock(SomeOtherClassProcessor02.class);
        mockSomeOtherClassProcessor03 =     mock(SomeOtherClassProcessor03.class);
    }

    @Test
    public void testingGet() throws Exception
    {
        date = new Date(); 
        //this is where I'm stuck
        Whitebox.setInternalState(mockMyClass,     "someOtherClassProcessor01", mockSomeOtherClassProcessor01);

    }
}

是否可以为此使用白盒?我需要确保在这些对象的 getter 中有一个调用。我应该尝试类似 when(someOtherClassProcessor01.doSomething(any(), date)).thenReturn(true) 吗?如果您需要更多详细信息,请告诉我。

编辑:甚至可以模拟私有枚举 SomeTypes?

【问题讨论】:

  • "甚至可以模拟私有枚举 SomeTypes"——不需要! UnitTests 验证行为,而不是代码!行为是返回值与依赖项通信。其他任何内容都是实现细节,您无需明确验证,因为它可能会因重构而改变。

标签: java unit-testing junit


【解决方案1】:

一种选择是使用反射将您自己的(模拟的)SomeOtherClassProcessor 实现替换为 MyClass

MyClass myClass = new MyClass();
SomeOtherProcessor01 mockProcessor01 = mock(SomeOtherProcessor01.class);

// reflection bit: find the field by its name
// handle NoSuchFieldException
Field someProcessorField = MyClass.getDeclaredField("someOtherProcessor01");
// the field is declared as private, so make it accessible in order to work with it
someProcessorField.setAccessible(true);
// now set your mocked processor into the field. 
// First argument is the object to change; second argument - new value for the field
someProcessorField.set(myClass, mockProcessor01);

PS。使用 PowerMock 和/或反射是屈服于糟糕的设计(根据 Timothy :)。您不应该依赖尚未经过良好测试的代码,如果是,您不应该再次尝试测试它。假设您的测试实际上揭示了一个错误 - 如果您不控制代码,您将如何修复它?假设 Java 11 变成了一个东西并且禁止你使用反射。假设您正在测试的代码发生更改并且字段被重命名 - 使用反射,您没有编译时安全性......潜在问题的列表还在继续

【讨论】:

  • 虽然这个答案在技术上是正确的,但您至少应该提到使用 PowerMock 和/或反射只是屈服于糟糕的设计
  • 我认为这已经被理解了,我当然是 100% 正确的。编辑了答案以说明这一点
  • 是的,我知道这是一个糟糕的设计,但这超出了我的控制范围。无论如何,谢谢你的帮助。
猜你喜欢
  • 2012-04-14
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 2021-09-16
  • 2023-03-10
  • 2014-10-02
  • 1970-01-01
相关资源
最近更新 更多