Java 是否可以调用模拟对象';什么方法?

Java 是否可以调用模拟对象';什么方法?,java,unit-testing,reflection,mockito,Java,Unit Testing,Reflection,Mockito,例如,我有一门课: public class A { private List<String> list; public A(B b){ list = b.getList(); } public List<String> someMethod(){ return list; } } 公共A类{ 私人名单; 公共服务A(B){ list=b.getList(); } 公共列表方法(){ 退货清单;

例如,我有一门课:

public class A {
    private List<String> list;

    public A(B b){
        list = b.getList();
    }

    public List<String> someMethod(){
        return list;
    }
}
公共A类{
私人名单;
公共服务A(B){
list=b.getList();
}
公共列表方法(){
退货清单;
}
}
我想在不调用构造函数的情况下对someMethod进行单元测试。我使用反射来设置
列表

问题是我不想创建
B
类对象,我不能模拟它,因为它会导致NPE

所以我的问题是:

如何在不调用
A的构造函数的情况下测试
someMethod
?有没有办法模拟类A并且不失去调用方法的可能性

使用零参数创建构造函数不是一个解决方案

注意:不想更改类的任何部分。我在问是否可以在不添加或更改类中任何内容的情况下执行此测试

我不想创建B类对象

添加不需要B的构造函数或工厂方法

public A(B b){
    this(b.getList());
}

/* package local */ A(List<String> list){
    this.list = list;
}

但是,除非您没有其他选择,例如反序列化,否则不建议这样做。

您应该模拟类的协作者——这意味着您可以创建被测试类的实例,并传入模拟,配置为在调用其方法时“做正确的事”

在您的示例中,您希望创建一个模拟B,并按如下方式使用它:

@RunWith(MockitoJUnitRunner.class)
class myTest {
  @Mock private B b;

  public void someMethod() {
    doReturn(new ArrayList<String>()).when(b).getList();
    A a = new A(b);
    assertEquals("result", a.someMethod().get(0));
  }
}
@RunWith(MockitoJUnitRunner.class)
类myTest{
@模拟二等兵B;
公共方法(){
doReturn(newarraylist()).when(b.getList();
A=新的A(b);
assertEquals(“result”,a.someMethod().get(0));
}
}

您可以测试类A,而无需Mockito调用它的构造函数。不确定我是否真的理解您的要求,但以下代码对我有效

import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ATest {

    @Test
    public void test() {
        A a = mock(A.class);
        when(a.someMethod()).thenCallRealMethod();
        List<String> listInA = new ArrayList<String>();
        ReflectionTestUtils.setField(a, "list", listInA);
        assertThat(a.someMethod(), is(listInA));
    }
}
import org.junit.Test;
导入org.springframework.test.util.ReflectionTestUtils;
导入java.util.ArrayList;
导入java.util.List;
导入静态org.hamcrest.CoreMatchers.is;
导入静态org.junit.Assert.assertThat;
导入静态org.mockito.mockito.mock;
导入静态org.mockito.mockito.when;
公开课考试{
@试验
公开无效测试(){
A=模拟(A.class);
当(a.someMethod())。然后调用realmethod();
List listInA=new ArrayList();
ReflectionTestUtils.setField(一个“列表”,列表);
断言(a.someMethod(),是(listInA));
}
}

在任何情况下,您都不应该将代码写入生产类中,这些代码将仅由测试使用。您应该在类似于生产的场景中测试类,并且应该只检查类似于生产的代码路径。使用零参数创建构造函数不是一个解决方案。我猜OP对这种方法也有同样的感觉。@EngineerDollery+1我同意,这是理想的,但并非所有项目都是理想的。根据A的进一步行为,您可能需要在arraylist中实际返回一些内容,但根据您的示例,这应该是可行的。问题是我根本不想模拟
B
。真正的
A
构造函数正在使用来自B及其文件的多个方法。它们用于设置
A
字段,因此我不想模拟
B
中的所有内容。我想我没有别的成就了。当然你的答案是正确的。如果答案正确,最好打勾。现在,如果您愿意,您可以创建一个B的实例作为间谍(使用@spy)——这将允许您仅模拟需要的方法。然而,在编写测试时,这是一个经常出现的问题——要编写单元测试,您需要/must/mock/stub协作者,否则您的测试就很脆弱。我印象深刻。这正是我想要的。谢谢
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ATest {

    @Test
    public void test() {
        A a = mock(A.class);
        when(a.someMethod()).thenCallRealMethod();
        List<String> listInA = new ArrayList<String>();
        ReflectionTestUtils.setField(a, "list", listInA);
        assertThat(a.someMethod(), is(listInA));
    }
}