我应该使用哪些方法进行JUnit测试 - 如何模拟具有许多依赖项的方法

时间:2016-11-18 16:05:37

标签: java unit-testing junit mocking mockito

我是JUnit的新手,并且不知道哪些方法应该有测试,哪些不应该。请看以下示例:

ORG  0x500;
BCF pclath,4;
BSF pclath,3;
CALL sub1_p1;
.
.
.
ORG 0x900;
sub1 :
 :
RETURN

public List<Site> getSites(String user) { SiteDao dao = new SiteDaoImpl(); List<Site> siteList = new ArrayList<Site>(); ServiceRequest rq = new ServiceRequest(); rq.setUser(user); try { ServiceResponse response = siteDAO.getReponse(rq); List<String> siteNums = response.getSiteNums(); if (siteNums != null && !siteNums.isEmpty()) { List<DbModelSite> siteInfo = dao.getSiteInfo(siteNums); if (siteInfo != null && !siteInfo.isEmpty()) { siteList = SiteMapper.mapSites(siteInfo); } } } catch (Exception e) { e.printStackTrace(); } return siteList; } public static List<Site> mapSites(List<DbModelSite> siteInfo) { List<Site> siteList = null; if (siteInfo != null && !siteInfo.isEmpty()) { siteList = new ArrayList<Site>(); for (DbModelSite temp : siteInfo) { Site currSite = mapSite(temp); siteList.add(currSite); } } return siteList; } public static Site mapSite(DbModelSite site) { Site mappedSite = null; if (site != null) { mappedSite = new Site(); mappedSite.setSiteNum(site.getSiteNum()); mappedSite.setSpace(site.getSpace()); mappedSite.setIndicator("Y"); } return mappedSite; } mapSites()方法进行单元测试非常简单,但我遇到问题的方法是使用mapSite()方法。对这种方法进行单元测试是否有意义?如果是这样,我该怎么做呢?看起来这需要相当多的嘲弄,因为我对JUnit很新,我无法弄清楚如何模拟所有这些对象。

所以我的问题实际上是两个方面:

  1. 如何确定方法是否需要进行单元测试?
  2. 一个单元如何测试需要大量模拟的复杂方法?

2 个答案:

答案 0 :(得分:3)

是的,测试该方法是有意义的。

能够测试它的第一件事就是使用依赖注入。如果该方法使用new创建自己的SiteDao实例,则无法告诉该方法使用SiteDao的另一个模拟实例。

因此,阅读依赖注入,并使用它。基本上,归结为

public class MyService {

    private SiteDao siteDao;

    public MyService(SiteDao siteDao) {
        this.siteDao = siteDao;
    }

    // use the siteDao passed when constructing the object, instead of constructing it
}

这样,在测试您的服务时,您可以

SiteDao mockSiteDao = mock(SiteDao.class);
SiteService service = new SiteService(mockSiteDao);

这里有一条与您的问题没有直接关系的建议,但会使您的代码更简单,也更容易测试:

  1. 永远不会从返回集合的方法返回null。返回一个空集合,表示“没有元素”。
  2. 通常,不要接受null作为有效的方法参数值,特别是如果参数是集合。
  3. 1和2的推论:遵循这些原则,您永远不需要检查集合的空或空。只需直接使用它。
  4. 这样可以减少代码混乱的if (siteNums != null && !siteNums.isEmpty())次数,并且您也可以减少要测试的分支数量。

    请注意,所有理智的库(JDK方法,JPA等)都遵循这些原则。例如,JPA查询永远不会返回空列表。

    此外,不要仅通过打印其堆栈跟踪并返回空列表来吞下异常,就好像没有发生任何错误一样。让异常传播,以便您可以注意并修复错误。

    想象一下,这种方法是一种返回医学分析系统发现的癌症肿瘤数量的方法。你真的希望系统告诉你你身体健康吗,而系统实际上由于例外而无法完成它的工作吗?我真的更喜欢系统说“我出了问题,使用另一台机器确定”。

答案 1 :(得分:0)

单元测试的想法是确保每个“单元”(通常是一种方法)可以单独测试,这样你就可以测试给定的输入你收到预期的输出,所以回答你的问题:

  1. 我应该说所有公共方法进行单元测试
  2. 如果你在方法上做了太多需要模拟的东西,那么你可能想要将功能分解为另一个类
  3. 回到你的例子,如果你想进行单元测试,有几件事要警惕:

    • new - 无论何时在方法中使用此关键字,您都会发现很难模拟该对象。在某些情况下(例如ServiceRequest),它很好,但在SiteDao之类的其他情况下,您会遇到问题。
    • 静态方法 - 同样的事情,使用SiteMapper.mapSites(siteInfo)你会发现很难模拟

    您可以使用PowerMock等库来模拟newprivatestatic方法,但我个人试图避免这种情况。