1

我正在处理一种设计情况,我不确定如何解决它,或者我的微设计是否有任何问题。

public abstract class A implements SomeFrameworkInterface {

  private final Param1 a1;

  @Inject
  private Param2 a2;

  protected A(Param1 a1) {
    this.a1 = a1;
  }

  @Override
  public someFrameworkInterfaceMethod() {
    //code
    doMyStuff();
  }

  protected abstract void doMyStuff();
} 

@Named
@SomeCustomAnnotation(property="someProperty")
public class B extends A {

  @Inject
  public B(Param1 b1) { //b1 is different for every implementation of class A, through some annotations
    super(b1);
  }

  @Override
  protected void doMyStuff() {
    //code
  }

}
  • 我需要将 A 类中的“@Inject Param2 a2”更改为通过构造函数注入,因此代码是可测试的,并且我将清除与此相关的代码异味。
  • 我不想从 B 构造函数发送它,因为我必须在 B 构造函数、A 构造函数和 A 的所有实现中的每个构造函数中再添加一个参数...但是子类永远不需要知道 Param2实例。
  • Param2 可能是静态的,但需要注入,因为它是组件(@Named),所以我没有找到静态注入的方法。

限制如下:

  1. 具有要使用的自定义注释和要实现的接口的第 3 方框架
  2. 代码必须是可测试的,因此不允许在字段上使用 @Inject/@Autowired
  3. 我们被限制使用在提到的自定义框架中“封装”的 Spring,因此我们只能使用纯 Java (JSR-330)。(如果 Spring 中有任何解决方案,也很高兴知道它)
4

2 回答 2

0

我找到了测试这个的解决方案,但它看起来有点奇怪。我的意思是我不明白为什么或如何发生这种情况,但它以一种干净的方式完成了这项工作。测试类看起来像:

@RunWith(MockitoJUnitRunner.class)
public BTest {

  @Mock
  private Param1 mockParam1;

  @Mock
  private Param2 mockParam2;

  @InjectedMocks
  private A b = new B(null);

  @Test
  public someFrameworkInterfaceMethodTest() {
    when(...).thenReturn(...)
    b.someFrameworkInterfaceMethod();
    verify(...).someCall(any());
  }

}

我很难弄清楚为什么Param1 a1仍然为空,并试图找出不同的解决方案。但似乎 Mockito 在构造后再次注入字段(在调用“new B(null)”之后 - 如果字段为空或不确定)。Param2 a2被 mockito 模拟,而Param1 a1保持为空,这是因为B 类中Param1 a1上的“ final ”关键字。

于 2018-04-12T14:37:37.297 回答
0

不通过 B 就不可能将任何参数传递给 A 的构造函数,因为您实际上是在构造 B 的实例。A 的构造函数仅被委托给以构造 B 实例的“A 部分”。

你能做的最多就是将某种“无类型”参数传递给 B 的构造函数,这样至少 B 不会知道Param2,但是即使我正在写下来,这种治疗听起来已经比疾病更糟糕了......

我没有看到注入Param2构建后使代码的可测试性降低。OTOH,使用静态字段肯定可以。

于 2018-04-11T13:59:22.507 回答