如何使用 JUnit 中的 public 方法测试私有字段设置为提供的值?

How to test private field is set to supplied value using public method in JUnit?

我有一个 class:

public class MyEncryptor {

    private StringEncryptor stringEncryptor; // this is an interface ref

    public void setStringEncryptor(StringEncryptor stringEncryptorImpl) {

        if(condition){
            this.stringEncryptor = stringEncryptorImpl;
        }

    }
}

在 JUnit 中测试方法 setStringEncryptor 时,我想测试实例值 stringEncryptor 是否设置为我在参数中提供的实现?或者我测试这个方法的方式不对?

以下是我在 junit 测试方法中失败的尝试:

MyEncryptor decryptor = new MyEncryptor ();

        StringEncryptor spbe = new StandardPBEStringEncryptor();
        decryptor.setStringEncryptor(spbe);

        Field f = MyEncryptor .class.getDeclaredField("stringEncryptor");
        f.setAccessible(true);

        Assert.assertSame(f, spbe);

我想测试stringEnctyptor在junit中设置为spbe

您给出的单元测试失败,因为您试图使用 assertSame 比较 Field 实例和 StandardPBEStringEncryptor 实例。你应该做的是:assertSame(f.get(decryptor), StandardPBEStringEncryptor)

请注意,我们使用 Field::get 方法来检索字段的值,我们提供的参数是我们要检索其字段值的实例。

然而,无论如何,对 setter 类型的方法进行单元测试是多余的,只是无缘无故地增加了额外的测试代码和测试时间。

这里您断言 java.lang.reflect.Field stringEncryptor 与您为测试创建的 StringEncryptor 对象是同一个对象:

StringEncryptor spbe = new StandardPBEStringEncryptor();
...
Field f = MyEncryptor .class.getDeclaredField("stringEncryptor");
f.setAccessible(true);
Assert.assertSame(f, spbe);

这是两个截然不同且不相关的两个截然不同的对象 类。
您应该首先检索与字段关联的值:

 Object value = f.get(spbe);

然后比较对象:

Assert.assertSame(value, spbe);

但无论如何我认为这不是好方法。
要测试代码,实现应该是可测试的。
只有在我们确实没有选择的情况下才应该进行反射来测试代码。
测试代码的一种自然方法是提供一种获取实际 StringEncryptor 字段的方法。

public StringEncryptor getStringEncryptor(){
     return stringEncryptor;
}

通过这种方式,您可以直接断言字段值。

i want to test if instance value stringEncryptor is set to what i've supplied in parameter as implementation? or i'm going the wrong way for testing this method?

我认为你走错了路。只要有可能,我都会测试被测单元是否按预期进行加密,而不是具体是否设置了私有字段。您真的想测试单元功能,而不是其实现的细节。