错误测试:无法初始化@Spy注释字段'资源' /设计建议

时间:2015-12-22 11:42:13

标签: unit-testing enums mockito

为什么我不能监视枚举方法?我可以嘲笑并监视我需要的所有其他内容,但是当我试图监视枚举时,我的测试不再运行,我只是得到初始化错误。

枚举类:

public enum DomainResource implements SoapUpdate {

 ENUM1(new PUpdate()),
 ENUM2(new SUpdate());

 private DomainResource(SoapUpdate update){
   this.update = update;
 }

 private final SoapUpdate update;

 @Override
 public void apply(SoapService svc, byte[] resp ) throws Exception {
   update.apply(svc, resp)
 }
}

要测试的课程:

public class ProcessUpdateMessage implements Function<UpdateMessage, MessageResult> {

  private DomainResource resource;

  public MessageResult apply( UpdateMessage t ){

    ..
    resource = getResourceType( t.getUrl() )
    ..
    resource.apply( soapService, dropwizardResponse );
  }

}

测试:

@RunWith(MockitoJUnitRunner.class)
public class UpdateMessageTest {

  // other spies and mocks working correctly

  @Spy
  DomainResource resource; // error here

  @InjectMocks
  ProcessUpdateMessage puma = new ProcessUpdateMessage(null, null, "");

  @Test
  ...
}

并且(我没有写过那个类)将逻辑放入java枚举中是不是很糟糕?

由于

2 个答案:

答案 0 :(得分:3)

Mockito doesn't allow mocking final classes,其中包含枚举effectively final。但是,错误在于ProcessUpdateMessage的设计,而不是枚举类型。

枚举类型,尤其是示例中的值名称很差,这可以解释为什么您对该代码的设计有疑问。但是,无论是谁写了枚举 DID都会给你一种模拟它的方法(正如你的评论建议你发现的那样),通过使它实现接口SoapUpdate。您需要将ProcessUpdateMessage.resource的类型更改为SoapUpdate,然后您至少可以模拟它(虽然查看您的代码我想知道在您的测试中,未显示,注入的模拟不会被getResourceType)的调用结果覆盖。

在回答关于最佳实践的最后一个问题时,在枚举值中添加逻辑完全符合DRY的最佳实践。枚举类型表示已知和有限的一组可能性中的选择。如果它是暗示行为的选择,您可以强制接收枚举的任何方法来实现容易出错且冗余的switch语句,指定枚举的所有可能值的行为,或者您可以让它调用方法关于枚举值。这是DRY的一个明显案例,它也会影响代码的cyclomatic complexity

答案 1 :(得分:0)

这是我的一个测试/我的解决方案:

@Test
public void testSoapServiceCallwithDWResponse200AndSoapProblem(){

  UpdateMessage um = new UpdateMessage( "ID/123", "POST" , "/domain/resourcename/id_123" );
  int status = 200;
  String jsonResp = "{aLotOf:\"json\"}";

  doReturn( response ) //mocked
  .when( connector ).getLatestStateOfResource( anyString() );

  prepareResponseMockedEntityAndStatus( status, jsonResp );

  MockResource mockResource = new MockResource( "exception - resp status "+status );

  doReturn( mockResource )
  .when( puma ).getResourceType( anyString() );

  MessageResult processingResult = puma.apply( um );

  // a few verify..

  Assert.assertTrue( mockResource.times() == 1 );

  Assert.assertTrue( processingResult == MessageResult.NACK_REQUEUE );

}


class MockResource implements SoapUpdate{  

  private String name;
  private int calls;

  public MockResource( String name ){
    this.name = name;
    calls = 0;
  }

  public int times(){
    return calls;
  }

  @Override
  public void apply( SoapService svc, byte[] resp ) throws Exception {

    calls++;

    if( name.contains( "exception" ) ){
      throw new Exception( name + " - Mocked `response.apply()` throws an excpt");
    }

    System.out.println( name + " - DB behind soap service UPDATED SUCCESSFULLY" );
  }

}