考虑我需要测试的类中的以下字段和方法。
private final static String pathToUUID = "path/to/my/file.txt";
public String getUuid () throws Exception {
return new String(Files.readAllBytes(Paths.get(pathToUUID)));;
}
UUID存储在应用程序首次运行时创建的文件中。CCD_ 1存在于由CCD_ 2指示的位置中。我正在为这个方法写一个单元测试。
@RunWith(PowerMockRunner.class)
@PrepareForTest({Files.class})
public class MyTest {
private final String expected = "19dcd640-0da7-4b1a-9048-1575ee9c5e39";
@Test
public void testGetUuid() throws Exception {
UUIDGetter getter = new UUIDGetter();
PowerMockito.mockStatic(Files.class);
when(Files.readAllBytes(any(Path.class)).thenReturn(expected.getBytes());
String retrieved = getter.getUuid();
Assert.assertEquals(expectedUUID, retrieved);
}
}
不幸的是,when().thenReturn()
在测试过程中没有被调用,测试作为集成测试执行,从文件系统读取文件并返回其值,而不是我期望的模拟值。但是,如果我在测试方法中伪造对Files.readAllBytes()
的调用,并将结果回显到控制台,则会显示expected
值。
那么,如何让我的方法在测试中使用PowerMock when()-thenReturn()
模式正常工作呢?
对于任何面临类似问题的人,我通过对我的测试类进行以下更改来解决这个问题:
@RunWith(PowerMockRunner.class)
@PrepareForTest({UUIDStasher.class})
public class TestUUIDStasher {
private final String expectedUUID = "19dcd640-0da7-4b1a-9048-1575ee9c5e39";
Path spoofPath = Paths.get("C:\DIRECTORY");
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(Paths.class);
PowerMockito.mockStatic(Files.class);
when(Paths.get(any(String.class))).thenReturn(spoofPath);
when(Files.readAllBytes(any(Path.class))).thenReturn(expectedUUID.getBytes());
}
@Test
public void testGetUUID() throws Exception {
UUIDStasher stasher = new UUIDStasher();
String retrieved = stasher.getUuid();
Assert.assertEquals(expectedUUID, retrieved);
}
}
您需要测试的类的编写方式很糟糕。路径不应该是硬编码的——使其可参数化——例如,通过构造函数注入路径。然后,在集成测试中,只需注入测试资源的路径,就可以开始了。没有PowerMock,没有黑客——简单的构造函数注入。
JDK类在使用PowerMock时很难处理。在你的情况下,我会这样做:
重构UUIDGetter
以添加一个用于测试目的的构造函数,该构造函数接受"uuid"文件的路径:
package so37059406;
import java.nio.file.Files;
import java.nio.file.Paths;
public class UUIDGetter {
private final static String PATH_TO_UUID = "path/to/my/file.txt";
private final String path;
public UUIDGetter() {
this(PATH_TO_UUID);
}
// for testing purposes
protected UUIDGetter(final String path) {
this.path = path;
}
public String getUuid() throws Exception {
return new String(Files.readAllBytes(Paths.get(this.path)));
}
}
然后这样测试:
package so37059406;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class UUIDGetterTest {
@Test
public void testGetUuid() throws Exception {
final UUIDGetter getter = new UUIDGetter(getClass().getClassLoader().getResource("so37059406/uuid.txt").getPath());
assertEquals("19dcd640-0da7-4b1a-9048-1575ee9c5e39", getter.getUuid());
}
}
有一个名为"so37059406/uuid.txt"的资源文件(在测试资源文件夹中),包含(没有行尾):
19dcd640-0da7-4b1a-9048-1575ee9c5e39
这是IMHO,更好,因为:
- 没有powermock:这是一个强大的工具,但它有价格(较慢的测试,可能的测试奇怪的交互
- 它更可读/更容易理解