任何人都可以帮我模拟一个返回一个对象的静态方法,这个静态方法存在于一个final类中

时间:2017-10-01 17:18:41

标签: junit powermock

我需要帮助以下事情,

我必须使用PowerMock / Mockito编写一个Junit,用于调用外部jar中存在的最终类的静态方法。

我需要编写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是最后一个类,而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

1 个答案:

答案 0 :(得分:0)

你必须准备最终的静态类。

以下是使用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上的调用将返回一些内容):

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

当前测试用例中此指令的版本依赖于代码传入StringReader的{​​{1}}与测试用例提供的模拟readFirstSectionAndClose之间的相等匹配。这些并不是平等的。因此,不满足模拟调用的期望,并且不会返回Reader

一些不相关的笔记:

  • 无需在mockSection中包含SomeClass.class,您只需要在该注释中包含要模拟的类,因为@PrepareForTest是您要尝试的类测试该课程不需要嘲笑。
  • 使用SomeClass实例@InjectMocks有点奇怪,因为SomeClass没有(模拟提供的)模拟注入它:)你可以用{{1}替换此声明}
  • 您提供的代码SomeClass具有私有范围,因此无法从SomeClass someClass = new SomeClass();进行测试(或以任何方式调用)。