1

在大多数情况下,当我考虑创建扩展时,都会遇到同样的问题:如何存储可变对象?这是我的问题:让我们考虑一下我的扩展提供了一个参数解析器,它为测试提供了一个可变对象。假设该对象具有更改配置的方法。基于JUnit 5 用户指南Javadoc的简单实现可能如下所示:

public class MyExtension implements ParameterResolver {
  private static final Namespace NAMESPACE = Namespace.create(MyExtension.class);

  public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
    return parameterContext.getParameter().getType() == MyMutableType.class;
  }

  public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
    return extensionContext.getStore(NAMESPACE).getOrComputeIfAbsent(MyMutableType.class, __ -> new MyMutableType());
  }
}

不幸的是,对于以下测试类,这个实现被破坏了。

@ExtendWith(MyExtension.class)
final class MyTest {
  @BeforeAll
  static void init(MyMutableType resolvedObject) {
  }

  @Test
  void test1(MyMutableType resolvedObject) {
    resolvedObject.changeSomeConfig();
    ...
  }

  @Test
  void test2(MyMutableType resolvedObject) {
    // resolvedObject might be affected by changed configuration in test1().
    ...
  }
}

直到今天,我都找不到好的解决方案。JUnit是否有一个指南应该如何工作。我什么也找不到。为了解决这个问题,我看到了两种方法。它们似乎都不适用于 JUnit 的 API。

ExtensionContext一种方法是在不特定于单个测试时禁止使用我的参数解析器。不幸的是,我找不到任何可靠的方法来检查它。我可以检查 @BeforeAll 之类的注释,但这更像是一种估计,而不是可靠的检查。

第二种方法是在我们输入更具体的对象时复制对象ExtensionContext。或者,我可以设置一个标志来防止进一步修改并提供有意义的错误消息。然而,这样的实现远非简单,看起来更像是滥用 API。除此之外,copyOperator在没有实际必要的情况下使用可能会过于严格。

<T> T getOrCompute(ExtensionContext extensionContext, Object key, Supplier<T> factory, UnaryOperator<T> copyOperator) {
  Store store = extensionContext.getStore(NAMESPACE);
  // Using remove() because it is the only method ignoring ancestors
  Object previous = store.remove(key);
  if (previous == null) {
    T fromAncestor = (T) store.get(key);
    if (fromAncestor == null) {
      T result = factory.get();
      store.put(key, result);
      return result;
    }
    else {
      T result = copyOperator.apply(fromAncestor);
      store.put(key, result);
      return result;
    }
  }
  else {
    store.put(key, previous);
    return (T) previous;
  }
}

我想知道我是否遗漏了一些重要的东西,或者 JUnit 是否没有有意义的方式来处理扩展中的可变状态。

4

0 回答 0