【问题标题】:Why JUnit test with Mockito work without defining "when" method?为什么使用 Mockito 进行 JUnit 测试而不定义“何时”方法?
【发布时间】:2018-07-13 08:11:27
【问题描述】:

我正在尝试使用空数据库/数据库没有返回任何内容来测试场景。

我用 mockito 写了一个 junit4 测试类。有mockito创建的服务类和dao类。起初,我定义了“when”方法并且它起作用了。后来,我尝试拉“何时”方法调用,看看会发生什么,它仍然有效。为什么?

当 myService.getDistinctObjectList() 被调用时,myService 类将调用 myDao 的所有四个方法。所以我想我必须模拟所有四种方法并返回虚拟结果。如果 myDao.someMethod() 在未配置的情况下被调用会发生什么? MyDao 应该与数据库一起工作,但我没有给它任何东西。

我附上了MyDao和MyService的示例代码供参考。 (我把它们简化了,MyDao 有四种方法,分别检索四种对象)

public class MyDaoImpl implements MyDao {
    @SuppressWarnings("unused")
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;
    private String schema;

    @ConstructorProperties({ "dataSource", "schema" })
    private MyDaoImpl(DataSource dataSource, String schema) {
        this.dataSource = dataSource;
        this.schema = schema;
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public List<SomeObjectTypeA> listSomeObjectTypeA() {
        return this.jdbcTemplate.query("select * from " + schema + ".SOME_TABLE", new RowMapper<SomeObjectTypeA>() {
            @Override
            public SoftBillAccount mapRow(ResultSet rs, int rowNum) throws SQLException {
                String memberA = rs.getString("MEMBER_A");
                String memberB = rs.getString("MEMBER_B");
            }
        });

    }
    public List<SomeObjectTypeA> listSomeObjectTypeB() {
        //omitted
    }
    public List<SomeObjectTypeA> listSomeObjectTypeC() {
        //omitted
    }
    public List<SomeObjectTypeA> listSomeObjectTypeD() {
        //omitted
    }
}

public class MyServiceImpl implements MyService {

    private MyDao myDao;

    public MyServiceImpl(){}

    @ConstructorProperties({ "myDao" })
    public MyServiceImpl(MyDao myDao) {
        this.myDao = myDao;
    }

    @Override
    public List<String> getSomeObjectTypeA_MemberA_Only() {
        List<SomeObjectTypeA> list = myDao.listSomeObjectTypeA();
        List<String> memberAList = new ArrayList<String>();
        for (SomeObjectTypeA objectA : list) {
            memberAList.add(objectA.getMemberA());
        }
        return memberAList;
    }
}



public class MyServiceImpl implements MyService {

    private MyDao myDao;

    public MyServiceImpl(){}

    @ConstructorProperties({ "myDao" })
    public MyServiceImpl(MyDao myDao) {
        this.myDao = myDao;
    }

    @Override
    public List<String> getSomeObjectTypeA_MemberA_Only() {
        List<SomeObjectTypeA> list = mydao.listSomeObjectTypeA();
        List<String> memberAList = new ArrayList<String>();
        for (SomeObjectTypeA objectA : list) {
            memberAList.add(objectA.getMemberA());
        }
        return memberAList;
    }
}

这是测试类:

public class Test1{

    @InjectMocks
    private MyServiceImpl myService;

    @Mock
    private MyDao myDao;

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

    @Test
    public void testEmptyDatabase() {

        //ArrayList<SomeObjectTypeA> list = new ArrayList<SomeObjectTypeA>();
        //list.add( new SomeObjectTypeA("A","A", "A", "A") );
        //when(myDao.listSomeObjectTypeA()).thenReturn( Collections.<SomeObjectTypeA>emptyList() );
        //when(myDao.listSomeObjectTypeB()).thenReturn( Collections.<SomeObjectTypeB>emptyList() );
        //when(myDao.listSomeObjectTypeC()).thenReturn( Collections.<SomeObjectTypeC>emptyList() );
        //when(myDao.listSomeObjectTypeD()).thenReturn( Collections.<SomeObjectTypeD>emptyList() );

        List<String> distinctList = myService.getDistinctObjectList(); // myService.getDistinctObjectList() end up calling all four methods of myDao

        //Write the List to a file, with a trailer with record count
        OutputWriter outputWriter = new OutputWriterImpl(outputFileDir, outputFilePrefix,outputFileSuffix);
        try{
            outputWriter.writeOutput(distinctList);
        }catch(IOException e){
            e.printStackTrace();
        }

        //Create a control file for comparison
        try{
            BufferedWriter bfr = new BufferedWriter(new FileWriter(compareFileDir+compareFilePrefix+compareFileSuffix));
            bfr.write("Trailer|");
            bfr.write(String.format("%07d", 0));
            bfr.newLine();
            bfr.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        File file1 = new File(outputFileDir + outputFilePrefix + date + outputFileSuffix);
        File file2 = new File(compareFileDir+ compareFilePrefix+compareFileSuffix);

        System.out.println(file1.length()); // show 17
        System.out.println(file2.length()); // show 17

        assertEquals(file1.length(), file2.length());
    }

【问题讨论】:

  • List distinctList = myService.getDistinctObjectList(); // myService.getDistinctObjectList() 最终调用 myDao 的所有四个方法,因为您的代码中甚至不存在该方法(也没有四个方法)如果您只显示大约四分之一,您希望我们如何开始猜测你的代码
  • 我没有看到 myDao 在您的测试中实际使用...
  • myDao 用于 myService。 List list = mydao.listSomeObjectTypeA(); // myDao,mydao 是一个类型

标签: java junit mockito


【解决方案1】:

除非您明确更改模拟的默认行为,否则它将返回 "nice values"。对于集合,默认返回值为空集合,因此您无需像注释掉的代码那样显式使用when 调用来返回此类空集合。

【讨论】:

  • 如果你在调试模式下查看myDao obkect,你会看到这个对象是一个mock对象。集合的模拟对象的默认行为是返回空集合。但我更喜欢使用 when 操作来获取空集合。
【解决方案2】:

如果没有调用 myDao.someMethod() 会发生什么 配置?

使用普通的 mockito(因此没有调用 read 方法的 spy 用法),它不会抛出任何异常或错误,它只会将该方法实现为空主体。然后,如果该方法被声明为void,则不需要额外的行为,并且如果该方法使用返回类型声明,它返回声明类型结果的默认值,即null 对象引用,但对于包含 Mockito 的集合返回它们的一个空实例,最后返回原语的默认值。

但请注意,Mockito 的此功能通常不会对您的测试逻辑造成任何副作用,因为通常您希望断言列表的内容而不仅仅是它们的非无效性。
但在你的情况下,你模拟空列表:

when(myDao.listSomeObjectTypeB()).thenReturn( Collections.<SomeObjectTypeB>emptyList() );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多