【问题标题】:Unit Testing: How to check non-constant arguments without forcing implementation单元测试:如何在不强制实施的情况下检查非常量参数
【发布时间】:2016-02-25 16:17:07
【问题描述】:

我正在为一个需要设置从现在起 24 小时后到期的警报的类编写单元测试。

我正在尝试以尽可能与实现无关的方式编写测试,这样它只会在它确实无法完成其工作时中断,而不是仅仅因为底层实现发生变化而中断。

所以我只模拟了对依赖项的最基本调用,例如获取对警报管理器的引用、创建待处理的意图等。

但是,当我尝试确认对 AlarmManager.set() 的呼叫实际上是在 24 小时后安排的时,我遇到了问题。 AlarmManager.set() 的第二个参数应该是警报到期的时间,当然,被测类必须计算出来。问题是有多种方法可以做到这一点(使用System.currentTimeMillis() + 24*60*60000,或GregorianCalendar alarmTime = new GregorianCalendar(); alarmTime.add(HOUR_OF_DAY, 24),或其他。

我可以尝试模拟对用于计算警报到期时间的方法之一的调用,以便我可以控制和计算对时间到期参数的精确期望。但是我模拟的任何方法都会在真实类中强制执行特定的实现。

我试图通过允许对警报时间进行模糊检查来绕过它——也就是说,使用我的测试代码来估计预期的警报时间,然后使用带有一些时间窗口的参数匹配器来允许执行时间。这会产生明显的竞争条件,这是不受欢迎的。我目前正在测量估计的闹钟时间和实际闹钟时间之间大约 25 到 30 毫秒的差异。

long alarmTime = System.currentTimeMillis() + 24*60*60000;
mMockAlarmManager.set(EasyMock.eq(AlarmManager.RTC),
                      EasyMock.and(EasyMock.geq(alarmTime), //<-- Lower Bound
                      EasyMock.leq(alarmTime+300)),         //<--Upper Bound
                      EasyMock.eq(mMockPendingIntent));

当然我可以玩时间窗口来使测试通过,但这对我来说感觉不对。在这种特殊情况下,我可以将窗口设置得相当宽并且没问题,因为我的程序并不关心闹钟时间是否准确——即使几分钟也可以。但这只是一个更大问题的简单示例,我相信我会在以后的单元测试中遇到这个问题。如果时间需要更准确,我会怎么做?如果参数不是时间,而是需要动态计算并且可以通过多种不同方式完成且都应该通过测试的其他东西,我会怎么做?

有没有更好的方法来检查非常量参数的计算是否正确,而不需要强制被测类使用特定实现的模拟?

编辑

我想明确我正在寻找的答案类型。显然,我可以修改被测类的实现以抽象出这个或那个。但这正在修改被测类,使其与测试无关。我正在寻找编写一个好的单元测试的方法,该测试只测试需求而不是实现。

考虑测试人员和开发人员是两个不同的人的情况,他们唯一的联系点是一个 API 和一组需求(假设它们都编写正确,等等……我知道现实世界通常是不同的)。测试人员如何在不知道实现的情况下编写单元测试?

所以我正在寻找修改测试的方法,而不是被测类。

【问题讨论】:

  • 为什么不创建一个简单的时间包装器(getter 和 setter 使用单一方法获取时间;System 或 GregorianCalendar)。当您构建警报时,将此时间对象作为参数传递。这具有将警报代码与时间源解耦的额外优势。

标签: java android unit-testing mocking


【解决方案1】:

如果您准备好这样做,您可以将下一个闹钟时间的计算转移到它自己的函数中,并在您的测试中模拟该函数的结果。这样,您可以确保您的函数在所需时间设置警报。要么这样,要么找到一种方法将当前时间作为参数传递,因为如果要准确预测结果,您需要一种方法让测试指定一个常数值。

由于在您的编辑中,您指定不想更改代码本身而只想修改测试,因此可以采用一系列可接受的值。除非一天的延迟精确到毫秒是至关重要的,否则拥有大范围的有效结果是完全可以接受的。

要记住的重要部分是,单元测试有助于确保您的代码根据您的测试工作,并且它不会在将来有人不知道的情况下中断。如果设置“从现在起的未来一天,给或花 5 分钟”的闹钟是可以接受的,那么继续这样做,然后继续做更​​重要的事情。单元测试带来的生产力收益很容易被过度吹嘘和吹毛求疵地浪费掉;你必须在某处画一条线。

【讨论】:

  • 参见 OP 编辑​​。但是,您的建议是合理的——我可能在这方面花费了太多时间。但我的问题是出于对比计算时间偏移更复杂的情况的担忧,以及将测试与实现隔离的有点哲学问题。
  • @rothloup 我已经编辑了我的答案,但底线保持不变,恐怕:)
  • 感谢您的意见,非常感谢。如果我找到更好的方法,我会发布。
猜你喜欢
  • 2018-02-08
  • 1970-01-01
  • 2017-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-14
  • 2023-01-09
相关资源
最近更新 更多