Java 如何在ExtensionContext.store中存储可变对象 在大多数情况下,当我考虑创建一个扩展时,我遇到了同样的问题:如何存储可变对象?这是我的问题:让我们考虑一下,我的扩展提供了一个参数解析器,它为测试提供了一个可变对象。假设对象具有更改配置的方法。基于和的简单实现可能如下所示: 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()); } }

Java 如何在ExtensionContext.store中存储可变对象 在大多数情况下,当我考虑创建一个扩展时,我遇到了同样的问题:如何存储可变对象?这是我的问题:让我们考虑一下,我的扩展提供了一个参数解析器,它为测试提供了一个可变对象。假设对象具有更改配置的方法。基于和的简单实现可能如下所示: 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()); } },java,junit,junit5,junit5-extension-model,Java,Junit,Junit5,Junit5 Extension Model,不幸的是,以下测试类的此实现已中断 @ExtendWith(MyExtension.class) final class MyTest { @BeforeAll static void init(MyMutableType resolvedObject) { } @Test void test1(MyMutableType resolvedObject) { resolvedObject.changeSomeConfig(); ... } @Tes

不幸的是,以下测试类的此实现已中断

@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;
  }
}
T getOrCompute(ExtensionContext ExtensionContext,对象键,供应商工厂,UnaryOperator copyOperator){
Store Store=extensionContext.getStore(名称空间);
//使用remove(),因为它是唯一忽略祖先的方法
Object previous=存储。删除(键);
如果(上一个==null){
T fromsentor=(T)store.get(key);
if(from祖先==null){
T result=factory.get();
存储。放置(键、结果);
返回结果;
}
否则{
T result=copyOperator.apply(来自祖先);
存储。放置(键、结果);
返回结果;
}
}
否则{
存储。放置(键,上一个);
返回(T)以前的值;
}
}

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

在我看来,您的规范似乎有矛盾之处。使用BeforeAll表明所有测试的参数都应该相同,但每个测试都应该有自己的实例。只有一个是可能的。你能澄清一下吗?@johanneslink这是一种看法。然后,问题是我——扩展的作者——无法验证它是如何使用的。如果我不想在
@BeforeAll
中使用我的参数解析器,我无法阻止它。@johanneslink另一个观点是,在某些情况下,我可以通过复制对象(如上所述)来支持这种用法,但实现看起来非常粗糙。无论我采用哪种方法,API似乎都缺少正确实现这两种方法的功能。至少如果我想在我的扩展被误用时以一条有意义的错误消息失败。(也许我应该把它分成两个问题。我把它分成一个问题,因为我现在想知道它打算如何使用,而不管实现的方法如何。)如果不在测试执行上下文中,可以检查扩展上下文的类型并拒绝解析参数。