我有这个类:
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() metthod怎么办,有什么方法可以验证调用吗?
使用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());
}
这个类的约定是:你提供模式作为字符串,类缓存编译的模式。因此,请专注于测试合约,而不是特定的实现(恰好使用映射)。
比如:
- 首先,编写将字符串转换为模式的测试:输入空的、空的、"简单"的字符串;然后检查预期的结果
- 对于缓存部分:使用
==
检查模式的相等引用!
换句话说:你想要测试该方法在推送相等的字符串时是否返回相同的模式。因此,您可以执行以下操作:
@Test
public void testCachig() {
Pattern first = CompliledPatterns.getPattern("whatever");
Pattern second = CompliledPatterns.getPattern("whatever");
assertThat(first, isSame(second));
}
isSame()是一个检查 refential equality 的 hamcrest 匹配器;换句话说;你在这里assertThat(first == second, is(true))
。
您希望避免检查该类的内部状态。这是一个实现细节。您只关心返回的相同对象。
如何实现这一点应该在您的测试用例中不可见。因为这样您就可以自由更改该实现,而无需更改测试用例!令人惊讶的是:这个东西完全不用使用模拟框架!
我同意 davidxxx 的观点:静态是良好 OO 中的异常。它导致紧密耦合并杀死多态性。仅在有充分理由时才使用它。