如何对使用 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() 可以在您定义的子类中覆盖你的测试。