任何人都可以帮助我模拟一个 returns 对象的静态方法,并且这个静态方法存在于最终的 class 中

Can any one help me in mocking a static method which returns an object, and this static method is present in a final class

我需要以下方面的帮助,

我必须使用 PowerMock/Mockito 为调用外部 jar 中存在的最终 class 的静态方法的方法编写 Junit。

我需要编写 JUnit 测试的方法是:

public class SomeClass {
    private PrivateKey privateKeyFromPkcs8(String privateKeyPem) throws IOException {
        Reader reader = new StringReader(privateKeyPem);
        Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY");
        if (section == null) {
            throw new IOException("Invalid PKCS8 data.");
        }
        byte[] bytes = section.getBase64DecodedBytes();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
        try {
            KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory();
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return privateKey;
        } catch (NoSuchAlgorithmException exception) {
        } catch (InvalidKeySpecException exception) {
        }
        throw new IOException("Unexpected exception reading PKCS data");
    }
}   

在上面的代码中 PemReader 是一个最终的 class 而 readFirstSectionAndClose(reader, "PRIVATE KEY")PemReader.

中是一个静态方法

我已经尝试编写如下所示的测试,但 Section object(section) 在调试时显示为 null。也许调用的是实际代码 (PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY")) 而不是模拟代码。

@RunWith(PowerMockRunner.class)
@PrepareForTest({SomeClass.class,PemReader.class})
public class SomeClassTest {
    @InjectMocks
    SomeClass mockSomeClass;

    @Mock
    private Reader mockReader;

    @Mock
    private Section mockSection;

    @Test
    public void testPrivateKeyFromPkcs8() throws Exception {   
        PowerMockito.mockStatic(PemReader.class);
        Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);

        assertNotNull(mockSomeClass.privateKeyFromPkcs8(dummyPrivateKey));
    } 

 }

请帮我用powermockito/mockito

写一个Junit

您必须准备最终静态class。

这是一个使用 JUnit 的 PowerMock 注释的示例:

@RunWith(PowerMockRunner.class)
@PrepareForTest({PemReader.class})
public class PemReaderTest {

    @Mock
    private Reader mockReader;

    @Mock
    private Section mockSection;

    @Test
    public void testMockingStatic() {
        PowerMockito.mockStatic(PemReader.class);

        Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);

        Assert.assertEquals(mockSection, PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY"));
    }
}

为了完整起见,这里是 PemReader 的定义:

public final class PemReader {

    public static Section readFirstSectionAndClose(Reader reader, String key) {
        return null;
    }
}

以上测试通过以下版本:

  • JUnit: 4.12
  • Mockito:2.7.19
  • PowerMock:1.7.0

更新 1:基于您更新的问题。如果您只是进行以下更改,您的测试用例将通过(或者至少 PemReader.readFirstSectionAndClose 上的调用将 return 某些东西):

Mockito.when(PemReader.readFirstSectionAndClose(
    Mockito.any(Reader.class), 
    Mockito.eq("PRIVATE KEY"))
).thenReturn(mockSection);

当前测试用例中此指令的版本依赖于代码传递给 readFirstSectionAndCloseStringReader 和测试用例提供的模拟 Reader 之间的相等匹配。这些不是 'equal',因此未满足模拟调用的期望,并且您的 mockSection 未被 returned。

一些无关的笔记:

  • 不需要在@PrepareForTest中包含SomeClass.class,你只需要在那个注释中包含你想模拟的classes,因为SomeClass是您要测试的 class class。
  • 不需要模拟
  • 使用 @InjectMocks 来实例化 SomeClass 有点奇怪,因为 SomeClass 没有(mockito 提供的)模拟注入它:) 你可以用 [= 替换这个声明28=]
  • 在您提供的代码中 SomeClass.privateKeyFromPkcs8 具有私有范围,因此无法从 SomeClassTest.
  • 对其进行测试(或以任何方式调用)