如何对使用 Java UUID 的代码进行单元测试?
How do I unit test code which uses Java UUID?
我有一段代码需要用 Java UUID (UUID.randomUUID()
) 填充响应对象的一个属性。
如何从外部对该代码进行单元测试以检查此行为?不知道里面会生成什么UUID
需要测试的示例代码:
// To test whether x attribute was set using an UUID
// instead of hardcode value in the response
class A {
String x;
String y;
}
// Method to test
public A doSomething() {
// Does something
A a = new A();
a.setX( UUID.randomUUID());
return a;
}
Powermock 和静态模拟是前进的方向。你需要这样的东西:
...
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
...
@PrepareForTest({ UUID.class })
@RunWith(PowerMockRunner.class)
public class ATest
{
...
//at some point in your test case you need to create a static mock
mockStatic(UUID.class);
when(UUID.randomUUID()).thenReturn("your-UUID");
...
}
请注意,静态模拟可以在使用 @Before 注释的方法中实现,因此它可以在所有需要 UUID 的测试用例中重复使用,以避免代码重复。
初始化静态模拟后,UUID 的值可以在您的测试方法中的某处断言,如下所示:
A a = doSomething();
assertEquals("your-UUID", a.getX());
当你需要 mock 时,class/static 方法真的很痛苦。我最终做的是使用一个薄包装器 class 和一个实现静态方法的接口。
在您的代码中,instantiate/inject 并使用包装器 class 而不是静态方法。这样你就可以用模拟替换它。
关于 ,似乎我能够成功模拟 UUID 的唯一方法是添加 class 我想在 [=11= 下测试]:
@PrepareForTesting({UUIDProcessor.class})
@RunWith(PowerMockitoRunner.class)
public class UUIDProcessorTest {
// tests
}
编辑:在获得更多单元测试经验后,我会选择 ThinkBonobo 的回答。创建一个接口,一个伪实现和一个具体实现,如下所示:
public interface UuidProvider {
UUID uuid();
class Fake implements UuidProvider {
@Override
public UUID uuid() {
return UUID.fromString("0000-00-00-00-000000");
}
}
}
public class RandomUuidProvider implements UuidProvider {
@Override
public UUID uuid() {
return UUID.randomUUID();
}
}
在您的测试中注入 UuidProvider.Fake
,并在您的生产代码中注入 RandomUuidProvider
。
或者在 Kotlin 中:
interface UuidProvider {
fun uuid(): UUID
class Fake : UuidProvider {
override fun uuid() = UUID.fromString("0000-00-00-00-000000")
}
}
class RandomUuidProvider : UuidProvider {
override fun uuid() = UUID.randomUUID()
}
下面是我的旧答案。
除了 ThinkBonobo 的响应之外,另一种创建 getter 方法(可选地用 @VisibleForTesting
注释)的方法例如 String getUUID()
可以在您定义的子类中覆盖你的测试。
我有一段代码需要用 Java UUID (UUID.randomUUID()
) 填充响应对象的一个属性。
如何从外部对该代码进行单元测试以检查此行为?不知道里面会生成什么UUID
需要测试的示例代码:
// To test whether x attribute was set using an UUID
// instead of hardcode value in the response
class A {
String x;
String y;
}
// Method to test
public A doSomething() {
// Does something
A a = new A();
a.setX( UUID.randomUUID());
return a;
}
Powermock 和静态模拟是前进的方向。你需要这样的东西:
...
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
...
@PrepareForTest({ UUID.class })
@RunWith(PowerMockRunner.class)
public class ATest
{
...
//at some point in your test case you need to create a static mock
mockStatic(UUID.class);
when(UUID.randomUUID()).thenReturn("your-UUID");
...
}
请注意,静态模拟可以在使用 @Before 注释的方法中实现,因此它可以在所有需要 UUID 的测试用例中重复使用,以避免代码重复。
初始化静态模拟后,UUID 的值可以在您的测试方法中的某处断言,如下所示:
A a = doSomething();
assertEquals("your-UUID", a.getX());
当你需要 mock 时,class/static 方法真的很痛苦。我最终做的是使用一个薄包装器 class 和一个实现静态方法的接口。
在您的代码中,instantiate/inject 并使用包装器 class 而不是静态方法。这样你就可以用模拟替换它。
关于
@PrepareForTesting({UUIDProcessor.class})
@RunWith(PowerMockitoRunner.class)
public class UUIDProcessorTest {
// tests
}
编辑:在获得更多单元测试经验后,我会选择 ThinkBonobo 的回答。创建一个接口,一个伪实现和一个具体实现,如下所示:
public interface UuidProvider {
UUID uuid();
class Fake implements UuidProvider {
@Override
public UUID uuid() {
return UUID.fromString("0000-00-00-00-000000");
}
}
}
public class RandomUuidProvider implements UuidProvider {
@Override
public UUID uuid() {
return UUID.randomUUID();
}
}
在您的测试中注入 UuidProvider.Fake
,并在您的生产代码中注入 RandomUuidProvider
。
或者在 Kotlin 中:
interface UuidProvider {
fun uuid(): UUID
class Fake : UuidProvider {
override fun uuid() = UUID.fromString("0000-00-00-00-000000")
}
}
class RandomUuidProvider : UuidProvider {
override fun uuid() = UUID.randomUUID()
}
下面是我的旧答案。
除了 ThinkBonobo 的响应之外,另一种创建 getter 方法(可选地用 @VisibleForTesting
注释)的方法例如 String getUUID()
可以在您定义的子类中覆盖你的测试。