Ana*_*ige 123 java mocking mockito
我是开发新手,特别是单元测试.我想我的要求很简单,但我很想知道别人的想法.
假设我有两个类似的 -
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
Run Code Online (Sandbox Code Playgroud)
假设我正在为测试First.doSecond()方法编写单元测试.但是,假设,我想像Mock这样的Second.doSecond()类.我正在使用Mockito来做这件事.
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
Run Code Online (Sandbox Code Playgroud)
我看到模拟没有生效,断言失败了.有没有办法模拟我想测试的类的成员变量.?
kit*_*yst 77
您需要提供一种访问成员变量的方法,以便传入模拟(最常见的方法是setter方法或带参数的构造函数).
如果您的代码没有提供这样做的方法,则TDD(测试驱动开发)会错误地考虑它.
Jan*_*ing 56
如果您无法更改代码,则无法执行此操作.但我喜欢依赖注入,Mockito支持它:
public class First {
@Resource
Second second;
public First() {
second = new Second();
}
public String doSecond() {
return second.doSecond();
}
}
Run Code Online (Sandbox Code Playgroud)
你的考试:
@RunWith(MockitoJUnitRunner.class)
public class YourTest {
@Mock
Second second;
@InjectMocks
First first = new First();
public void testFirst(){
when(second.doSecond()).thenReturn("Stubbed Second");
assertEquals("Stubbed Second", first.doSecond());
}
}
Run Code Online (Sandbox Code Playgroud)
这非常好,很容易.
sou*_*eck 33
如果你仔细查看你的代码,你会发现second你的测试中的属性仍然是一个实例Second,而不是一个模拟(你没有first在你的代码中传递模拟).
最简单的方法是second在First类中创建一个setter 并明确地传递mock.
像这样:
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
public void setSecond(Second second) {
this.second = second;
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
....
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
first.setSecond(sec)
assertEquals("Stubbed Second", first.doSecond());
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是将Second实例作为First构造函数参数传递.
如果您无法修改代码,我认为唯一的选择是使用反射:
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
Field privateField = PrivateObject.class.
getDeclaredField("second");
privateField.setAccessible(true);
privateField.set(first, sec);
assertEquals("Stubbed Second", first.doSecond());
}
Run Code Online (Sandbox Code Playgroud)
但你可能会这样做,因为很少对你无法控制的代码进行测试(尽管人们可以想象你必须测试外部库的情况,因为它的作者没有:))
如果你不能改变成员变量,那么另一种方法是使用powerMockit并调用
Second second = mock(Second.class)
when(second.doSecond()).thenReturn("Stubbed Second");
whenNew(Second.class).withAnyArguments.thenReturn(second);
Run Code Online (Sandbox Code Playgroud)
现在问题是任何对新Second的调用都将返回相同的模拟实例.但在你的简单情况下,这将有效.
小智 6
我有同样的问题,因为没有设置私有值,因为Mockito没有调用超级构造函数.这是我如何通过反思来增强模拟.
首先,我创建了一个TestUtils类,其中包含许多有用的工具,包括这些反射方法.每次实现反射访问都有点不稳定.我创建了这些方法来测试项目上的代码,由于某种原因,这些方法没有模拟包,我没有被邀请包含它.
public class TestUtils {
// get a static class value
public static Object reflectValue(Class<?> classToReflect, String fieldNameValueToFetch) {
try {
Field reflectField = reflectField(classToReflect, fieldNameValueToFetch);
reflectField.setAccessible(true);
Object reflectValue = reflectField.get(classToReflect);
return reflectValue;
} catch (Exception e) {
fail("Failed to reflect "+fieldNameValueToFetch);
}
return null;
}
// get an instance value
public static Object reflectValue(Object objToReflect, String fieldNameValueToFetch) {
try {
Field reflectField = reflectField(objToReflect.getClass(), fieldNameValueToFetch);
Object reflectValue = reflectField.get(objToReflect);
return reflectValue;
} catch (Exception e) {
fail("Failed to reflect "+fieldNameValueToFetch);
}
return null;
}
// find a field in the class tree
public static Field reflectField(Class<?> classToReflect, String fieldNameValueToFetch) {
try {
Field reflectField = null;
Class<?> classForReflect = classToReflect;
do {
try {
reflectField = classForReflect.getDeclaredField(fieldNameValueToFetch);
} catch (NoSuchFieldException e) {
classForReflect = classForReflect.getSuperclass();
}
} while (reflectField==null || classForReflect==null);
reflectField.setAccessible(true);
return reflectField;
} catch (Exception e) {
fail("Failed to reflect "+fieldNameValueToFetch +" from "+ classToReflect);
}
return null;
}
// set a value with no setter
public static void refectSetValue(Object objToReflect, String fieldNameToSet, Object valueToSet) {
try {
Field reflectField = reflectField(objToReflect.getClass(), fieldNameToSet);
reflectField.set(objToReflect, valueToSet);
} catch (Exception e) {
fail("Failed to reflectively set "+ fieldNameToSet +"="+ valueToSet);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后我可以用这样的私有变量来测试类.这对于模拟您无法控制的深层树很有用.
@Test
public void testWithRectiveMock() throws Exception {
// mock the base class using Mockito
ClassToMock mock = Mockito.mock(ClassToMock.class);
TestUtils.refectSetValue(mock, "privateVariable", "newValue");
// and this does not prevent normal mocking
Mockito.when(mock.somthingElse()).thenReturn("anotherThing");
// ... then do your asserts
}
Run Code Online (Sandbox Code Playgroud)
我在页面中修改了我的实际项目中的代码.可能存在一两个编译问题.我想你得到了一般的想法.如果您觉得有用,请随意获取代码并使用它.
您可以使用 Mockito Mock 来模拟 Mockito Mock 的成员变量 ReflectionTestUtils
ReflectionTestUtils.setField(yourMock, "memberFieldName", value);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
212371 次 |
| 最近记录: |