使用@InjectMocks注入String属性

Sam*_*nes 25 java spring unit-testing dependency-injection mockito

我有一个@Controller带有这个构造函数的Spring MVC :

@Autowired
public AbcController(XyzService xyzService, @Value("${my.property}") String myProperty) {/*...*/}
Run Code Online (Sandbox Code Playgroud)

我想为这个Controller编写一个独立的单元测试:

@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {

    @Mock
    private XyzService mockXyzService;

    private String myProperty = "my property value";

    @InjectMocks
    private AbcController controllerUnderTest;

    /* tests */
}
Run Code Online (Sandbox Code Playgroud)

有没有办法@InjectMocks注入我的String属性?我知道我不能模拟一个字符串,因为它是不可变的,但我可以在这里注入一个普通的字符串吗?

@InjectMocks在这种情况下,默认情况下会注入null.@Mock如果我戴上它,可以理解地抛出异常myProperty.是否有另外一个注释我错过了只是意味着"注入这个确切的对象而不是它的模拟"?

小智 30

您无法使用Mockito执行此操作,但Apache Commons实际上可以使用其内置实用程序之一来实现此目的.你可以将它放在JUnit中的一个函数中,该函数在Mockito注入其余的模拟之后但在测试用例运行之前运行,如下所示:

@InjectMocks
MyClass myClass;

@Before
public void before() throws Exception {
    FieldUtils.writeField(myClass, "fieldName", fieldValue, true);
}
Run Code Online (Sandbox Code Playgroud)


jeb*_*det 17

由于您使用的是 Spring,因此您可以使用org.springframework.test.util.ReflectionTestUtils来自spring-test模块的 。它巧妙地包装了在对象上设置字段或在类上设置静态字段(以及其他实用程序方法)。

@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {

    @Mock
    private XyzService mockXyzService;

    @InjectMocks
    private AbcController controllerUnderTest;

    @Before
    public void setUp() {
        ReflectionTestUtils.setField(controllerUnderTest, "myProperty", 
               "String you want to inject");
    }

    /* tests */
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*lst 8

你不能用Mockito做到这一点,因为,正如你自己提到的,a Stringfinal和不能被嘲笑.

有一个@Spy注释适用于真实物体,但它有相同的限制@Mock,因此你不能窥探String.

没有注释告诉Mockito只是注入该值而不进行任何嘲弄或间谍活动.不过,这将是一个很好的功能.也许在Mockito Github存储库中建议它.

如果您不想更改代码,则必须手动实例化控制器.

进行基于纯注释的测试的唯一方法是重构控制器.它可以使用仅包含该属性的自定义对象,也可以使用具有多个属性的配置类.

@Component
public class MyProperty {

    @Value("${my.property}")
    private String myProperty;

    ...
}
Run Code Online (Sandbox Code Playgroud)

这可以注入控制器.

@Autowired
public AbcController(XyzService xyzService, MyProperty myProperty) { 
    ... 
}
Run Code Online (Sandbox Code Playgroud)

你可以模拟并注入它.

@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {

    @Mock
    private XyzService mockXyzService;

    @Mock
    private MyProperty myProperty;

    @InjectMocks
    private AbcController controllerUnderTest;

    @Before
    public void setUp(){
        when(myProperty.get()).thenReturn("my property value");
    }

    /* tests */
}
Run Code Online (Sandbox Code Playgroud)

这不是很直接,但至少你可以通过一点点存根进行纯粹的基于注释的测试.


小智 5

在这种情况下不要使用@InjectMocks。

做:

@Before
public void setup() {
 controllerUnderTest = new AbcController(mockXyzService, "my property value");
}
Run Code Online (Sandbox Code Playgroud)