如何从java.util包中模拟UUID.randomUUID()?



UUID.randomUUID()有什么问题 - 它不能被嘲笑

可以嘲笑吗?或者我的来源有误?

看例子:

1( 测试的类

package com.grayen;
import java.util.UUID;
public class TestedClass {
public UUID getUuid() {
return UUID.randomUUID();
}
public UUID getUuidFromWrapper() {
return UuidWrapper.randomUUID();
}
}

一种方法对 UUID 使用包装器,我可以模拟该包装器!

2( 真实 UUID 的包装器(所有修饰符都相同(

package com.grayen;
import java.util.UUID;
public final class UuidWrapper {
public static UUID randomUUID() {
return UUID.randomUUID();
}
}

3( 测试(最后一个注释行引发异常(

package com.grayen;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
@PrepareForTest({UUID.class, UuidWrapper.class})
@RunWith(PowerMockRunner.class)
public class TestedClassTest {
@Test
public void testMethod() {
UUID uuid = UUID.randomUUID();
PowerMockito.mockStatic(UUID.class);
PowerMockito.mockStatic(UuidWrapper.class);
PowerMockito.when(UUID.randomUUID()).thenReturn(uuid);
PowerMockito.when(UuidWrapper.randomUUID()).thenReturn(uuid);
TestedClass testedClass = new TestedClass();
assertEquals(uuid, testedClass.getUuidFromWrapper());
//assertEquals(uuid, testedClass.getUuid());
}
}

模拟静态方法始终是一种脆弱的方法。如果可能,最好使用非静态 UUID 源,这样就可以很容易地模拟它。

例如:

/**
* A source of new {@link UUID} instances.
*/
public interface UuidSource {
/**
* Returns a new {@link UuidSource} that generates UUIDs using {@link UUID#randomUUID}.
*/
public static UuidSource random() {
return UUID::randomUUID;
}
/**
* Returns a new {@link UUID} instance.
*
* <p>The returned value is guaranteed to be unique.
*/
UUID newUuid();
}

然后你可以把它注入到TestedClass,或者TestedClass有一个私有成员:

public class TestedClass {
private UuidSource uuidSource = UuidSource.random();
public UUID getUUID() {
return uuidSource.newUuid();
}
// etc.
}

然后要测试它,你可以有一个仅测试的构造函数,以允许注入模拟UuidSource,或者你可以直接替换uuidSource字段的值(通过扩大其可见性或使用反射或其他东西(。

作为奖励:这会将您的实际生产代码与UUID.randomUUID()分离。如果以后您决定需要使用版本 2 UUID(基于日期时间(或其他版本而不是随机 UUID,您也可以在生产代码中轻松更改它。这就是人们说使代码更易于测试通常会导致更好的整体设计时的意思。

所以我拿了你的代码并让它工作。您需要做的就是将TestedClass.class添加到您的@PrepareForTest中。

package com.grayen;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
@PrepareForTest({
UUID.class, 
UuidWrapper.class, 
TestedClass.class
})
@RunWith(PowerMockRunner.class)
public class TestedClassTest {
@Test
public void testMethod() {
UUID uuid = UUID.randomUUID();
PowerMockito.mockStatic(UUID.class);
PowerMockito.mockStatic(UuidWrapper.class);
PowerMockito.when(UUID.randomUUID()).thenReturn(uuid);
PowerMockito.when(UuidWrapper.randomUUID()).thenReturn(uuid);
TestedClass testedClass = new TestedClass();
assertEquals(uuid, testedClass.getUuidFromWrapper());
assertEquals(uuid, testedClass.getUuid());
}
}

编辑

我没有看到评论,但k5_指出了。

最新更新