在Java / Mockito中验证对未模拟对象的调用

时间:2017-06-23 06:28:22

标签: java mocking mockito

我有这堂课:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

class CompliledPatterns {
   private static final Map<String, Pattern> compiledPatterns = new ConcurrentHashMap<>();

   public static Pattern getPattern(String regex) {
       Pattern pattern = null;
       if (regex != null) {
           pattern = compiledPatterns.get(regex);
           if (pattern == null) {
               pattern = Pattern.compile(regex);
               compiledPatterns.putIfAbsent(regex, pattern);
           }
       }
       return pattern;
   }
}

现在我想为此编写测试用例。有什么可能的测试用例?

如果将重复的正则表达式传递给测试类中的getPattern()方法,有什么方法可以验证调用?

2 个答案:

答案 0 :(得分:2)

使用static修饰符来测试方法,您将很难以自然的方式为所有测试设置上下文。
当类加载一次时,您将保持测试方法之间的上下文 并且您需要设置上下文,因为您的类具有状态:compiledPatterns Map字段。

第一步:删除静态修饰符

private final Map<String, Pattern> compiledPatterns = new ConcurrentHashMap<>();

public Pattern getPattern(String regex) {
   Pattern pattern = null;
   if (regex != null) {
       pattern = compiledPatterns.get(regex);
       if (pattern == null) {
           pattern = Pattern.compile(regex);
           compiledPatterns.putIfAbsent(regex, pattern);
       }
   }
   return pattern;
}

第二步:要进行单元测试,你必须知道被测物体的状态 在调用getPattern()方法后,您应该有办法检查compiledPatterns Map字段的内容,以了解您的实施是否已执行它应该执行的操作。

要实现它,您可以提供支持compiledPatterns Map字段的视图(不可修改的地图)。

public Map<String, Pattern> compiledPatterns getCompiledPatternsView(){
   return Collections.unmodifiableMap(compiledPatterns);
}

在断言中,使用它。

例如,对于这个基本场景:当第一次传递正则表达式时,它会缓存在地图中。

测试方法可以是例如:

@Test
public void getPattern_with_first_time_passed_caches_and_returns_the_pattern(){
   CompliledPatterns compliledPatterns = new CompliledPatterns();
   String regex = "\\s+\\d+";
   Assert.assertTrue(compliledPatterns.getCompiledPatternsView().isEmpty());
   // action
   compliledPatterns.getPattern(regex); 
   //assertion
   Assert.assertEquals(1, compliledPatterns.getCompiledPatternsView().size());    
   Assert.assertEquals(regex, compliledPatterns.getCompiledPatternsView().get(regex).pattern());
}

答案 1 :(得分:1)

此类的契约是:您将模式提供为字符串,并且该类缓存已编译的模式。因此,请专注于测试合同,而不是特定的实施(恰好使用地图)。

喜欢在:

  • 首先编写用于将字符串转换为模式的测试:推入null,空,“简单”字符串;然后检查预期的结果结果
  • 和缓存部分:使用==检查模式的相同引用!

换句话说:在推动相等字符串时,您希望测试该方法返回相同的模式。所以你可以这样做:

@Test
public void testCachig() {
  Pattern first = CompliledPatterns.getPattern("whatever");
  Pattern second = CompliledPatterns.getPattern("whatever");
  assertThat(first, isSame(second));
}

isSame()是一个检查refential相等的hamcrest匹配器;换一种说法;你assertThat(first == second, is(true))来这里。

您希望避免检查该类的内部状态。这是一个实现细节。您只关心返回的相同对象。

如果在您的测试用例中可见,该如何实现。因为那时您可以自由地更改该实现,而无需更改测试用例!并且惊讶:没有使用模拟框架,这个东西完全有效!

我同意davidxxx: static 是一个好的OO异常。它导致紧密耦合并杀死多态性。只有在你有充分理由的情况下才能使用它。