【问题标题】:Java/Spring: initMocks a class which got @Value from yml fileJava/Spring:initMocks 一个从 yml 文件中获取 @Value 的类
【发布时间】:2020-02-18 22:00:45
【问题描述】:

我正在编写如下服务类的单元测试:

@Component
@Profile({"default", "dev"})
public class MyService {
    @Value("${my.property}")
    private String property;

    private OtherService otherService;

    public void MyMethod() {
        String myVar = otherService.method();

        return String.format("MyVar %s & MyProperty %s", myVar, property);
    }
}

我当前的测试类是这样的:

@ActiveProfiles("dev")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MyApplication.class)
public class MyServiceTest {
    @Mock
    private OtherService otherService;

    @InjectMocks
    private MyService myService;

    @BeforeEach() 
    public void init() {
        MockitoAnnotations.initMocks(this);

        when(otherService.method()).thenReturn("a string");
    }

    @Test
    public void shouldReturnException() {
        final Exception exception = assertThrows(ApiErrorException.class,
        () -> myService.myMethod(var));

    assertThat(exception).hasMessage("here the message");

    verify(otherService, never()).method();
    }
}

有了这两个类,我有一个application.ymlapplication-dev.yml 来设置my.property。 我想在测试执行期间从 application-dev 文件中获取属性。 但是,对于@InjectMocks,属性为空。然而,使用@Autowired 代替/使用@InjectMocks,属性变量设置为文件中存在的值。

问题,使用带有/代替 InjectMock 的 Autowired 会导致 otherService 变量被初始化,因此不会创建模拟。

如何在使用文件中的值设置属性变量的同时仍然使用 Mockito? 我看到了ReflectionTestUtils.setField,但使用它意味着不使用 yml 文件(我不是粉丝)。

祝你有美好的一天


在@Deadpool 的帮助下,测试可以使用application.yml 文件中写入的值。 但是,使用@MockBean@Autowired,测试会得到我不理解的行为。

示例: 我测试一个方法是否返回异常,并验证在捕获异常后没有调用其他方法:verify(otherService, never()).otherMethod(); 写入此行会返回以下错误org.mockito.exceptions.verification.NeverWantedButInvoked

初始异常被正确捕获,但测试似乎不承认必须调用其他服务。

【问题讨论】:

    标签: java spring mockito


    【解决方案1】:

    @SpringBootTest 用于集成测试,它加载将用于测试环境的ApplicationContext

    当我们需要引导整个容器时,可以使用@SpringBootTest 注解。注释通过创建将在我们的测试中使用的 ApplicationContext 起作用。

    由于您使用@SpringBootTest 生成集成环境,因此您需要使用@MockBean 注释模拟bean

    @ActiveProfiles("dev")
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = MyApplication.class)
    public class MyServiceTest {
    
       @MockBean
       private OtherService otherService;
    
       @Autowire
       private MyService myService;
    
       @BeforeEach
       public void init() {
    
        when(otherService.method()).thenReturn("a string");
       }
    }
    

    【讨论】:

    • 谢谢,它工作得非常好^^' 使用来自application.yml 的值的测试工作正常,但另一个测试由于使用verify(repository).save(any(MyClass.class)); 而失败。我正在寻找修复它
    • 如果没有看到代码和正确的错误消息,我无法判断,您可以使用适当的信息问其他问题@Baerrow
    • 我举个例子
    【解决方案2】:

    我建议您更改您的 MyService 类以通过构造函数或通过 setter 接受 OtherService。像这样的:

    @Component
    @Profile({"default", "dev"})
    public class MyService {
        @Value("${my.property}")
        private String property;
    
        private OtherService otherService;
    
        public MyService(OtherService otherService) {
            this.otherService = otherService
        }
    
        public void MyMethod() {
            String myVar = otherService.method();
    
            return String.format("MyVar %s & MyProperty %s", myVar, property);
        }
    }
    

    然后你像这样进行测试:

    @ActiveProfiles("dev")
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = MyApplication.class)
    public class MyServiceTest {
        @Mock
        private OtherService otherService;
    
        @InjectMocks
        @Autowired
        private MyService myService;
    
        @BeforeEach() 
        public void init() {
            MockitoAnnotations.initMocks(this);
    
            when(otherService.method()).thenReturn("a string");
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-17
      • 2021-05-19
      • 1970-01-01
      • 2012-09-07
      • 2015-07-10
      • 2012-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多