【问题标题】:Is there any other approach to mock this method call in constructor有没有其他方法可以在构造函数中模拟这个方法调用
【发布时间】:2019-01-20 07:42:17
【问题描述】:

我有这门课: SqssReadderApp

 @Autowired
    private Source source;
    @Autowired
    private AWSProperties awsProperties;
    @Autowired
    private AuditRepository auditRepository;
    private AmazonSQS sqs;

    @Autowired
    public SqssreaderApplication(AWSConfig awsConfig) {
        this.sqs = awsConfig.generateSQS();
    }

它从其构造函数调用方法 generateSQS()。 SQS 是通过调用静态方法生成的。 这是包含该方法的相关类:

   @Autowired
    private AWSProperties awsProperties;

    @Bean
    AmazonSQS generateSQS() {
        return AmazonSQSClientBuilder.standard()
                .withRegion(awsProperties.getQueueRegion())
                .build();
    }

现在,在我的测试类中,我试图通过注入一个 mockAwsConfig 来模拟这个 generateSQS() 方法调用。 我认为有两种方法可以在 SqssReaderApplication 中注入 mockSqs 实例。

方法一: 我将 mockAwsConfig 注入构造函数并使用以下规则对其进行初始化:

when(mockAwsConfig.generateSQS()).thenReturn(mockSQS);
SqssReaderApplication app = new SqssReaderApplication(mockAwsConfig);

问题: 所有剩余的 (@Autowired) 实体都保持为空。

方法 2: 我@Autowired SqssReaderApplication,所有其他字段都被模拟了,但是 SqssReaderApplication 中的 sqs 实例仍然为空。

**TestClass**:

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@TestPropertySource(locations = "classpath:application-test.properties")
@SpringBootTest
@ContextConfiguration(classes = {SqssreaderApplication.class,
        DefaultFrameworkSupport.class, AWSConfig.class, AuditRepository.class, FileProcessAuditLog.class})
public class SqssreaderApplicationTests {

    @Autowired
    private Source source;

    @MockBean
    AuditRepository auditRepository;
    @Mock
    private AmazonSQSClient amazonSQS;
    @Mock
    private AWSConfig awsConfig;

    @InjectMocks
    private SqssreaderApplication app;
    @Mock
    private AWSProperties awsProperties;

    @Before
    public void setup(){
        MockitoAnnotations.initMocks(this);
        when(awsConfig.generateSQS()).thenReturn(amazonSQS);
        app = new SqssreaderApplication(awsConfig);
    }

我也看到了其他答案,但它们在这种情况下不起作用。 有什么其他方法可以解决这个问题?我应该如何在 SqssReaderApp 中注入模拟,最好不使用 PowerMock 或修改源代码?

【问题讨论】:

    标签: java spring mocking mockito


    【解决方案1】:

    您正在混合使用两种依赖注入方式 (https://en.wikipedia.org/wiki/Dependency_injection#Three_types_of_dependency_injection)。您应该创建正确的构造函数,并且只有这个构造函数应该是@Autowired。 你的类应该是这样的:

    private Source source;
    private AWSProperties awsProperties;
    private AuditRepository auditRepository;
    private AmazonSQS sqs;
    
    @Autowired
    public SqssreaderApplication(Source source, AWSProperties awsProperties, AuditRepository auditRepository, AWSConfig awsConfig) {
        this.sqs = awsConfig.generateSQS();
    

    然后在您的测试中,您可以修改您的#1 方法并通过构造函数添加所有必需的模拟。 Little offtop:您在 AWSConfig 和 SqssreaderApplication 类中都使用 AWSProperties。在 SqssreaderApplication 中检查你是否真的需要它。

    【讨论】:

      【解决方案2】:

      AmazonSQS也是一个spring bean,可以用@Autowired注入。所以你可以改变构造函数

      @Autowired
      public SqssReadderApp(AWSConfig awsConfig) {
          this.sqs = awsConfig.generateSQS();
      }
      

      @Autowired
      public SqssReadderApp(AmazonSQS sqs) {
          this.sqs = sqs;
      }
      

      现在您可以将模拟实例注入构造函数。

      您还应该考虑解决这种字段注入和构造函数注入的混合问题。我推荐构造函数注入,这使得测试更容易。

      public class SqssReadderApp {
      
          @Autowired
          public SqssReadderApp(Source source, AWSProperties awsProperties, AuditRepository auditRepository, AmazonSQS sqs) {
              //
          }
      }
      

      另见why field injection is evil

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-06
        • 2012-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多