Java Concordion 子字符串 ("contains") 的解决方法
Workaround for Java Concordion substring ("contains")
如我所见,Concordion 测试框架仅进行精确 strings/numbers 匹配。
是否有任何解决方法来测试结果包含一些子字符串?
例如,我测试服务 returns 格式错误 ERROR 123
,测试应该对任何错误号都有效。
为了测试你的逻辑,你可以去
http://www.vogella.com/tutorials/Mockito/article.html
根据所需的输出可读性和您要投入的工作量,有多种答案。
1) 最简单的是使用assert-true
来检查子字符串,例如:
The service [returns](- "#result=callService()") an [ERROR](- "c:assert-true=containsSubstring(#result, #TEXT)")
夹具:
@RunWith(ConcordionRunner.class)
public class Whosebug {
public String callService() {
// call your service here
}
public boolean containsSubstring(String input, String check) {
return input.contains(check);
}
}
这样做的缺点是,如果失败,错误消息只会显示:
2) 与 1 相同的夹具,containsSubstring
在失败时抛出异常。然后 Concordion 会将失败显示为堆栈跟踪:
public boolean containsSubstring(String input, String check) {
if (!input.contains(check)) {
throw new AssertionError("'" + input + "' does not contain '" + check + "'");
}
return true;
}
失败时显示:
3) 使用assertEquals
检查:
The service [returns](- "#result=callService()") an [ERROR](- "?=contains(#result, #TEXT)")
夹具:
public String contains(String input, String check) {
if (!input.contains(check)) {
return input;
}
return check;
}
这显示 "best" 错误消息:
4) 你可以写一个扩展,这样你就不用在每个装置中定义这样一个 contains
方法(或者从一个超类装置中继承它们):
规格:
The service [returns](- "#result=callService()") an [ERROR](- "cx:isError=#result")
夹具:
@RunWith(ConcordionRunner.class)
@ConcordionOptions(declareNamespaces={"cx", "urn:error-extension:2017"})
@Extensions(ErrorExtension.class)
public class Whosebug {
public String callService() {
// call your service here
}
}
分机:
public class ErrorExtension implements ConcordionExtension {
private List<AssertListener> listeners = new ArrayList<AssertListener>();
public void addAssertEqualsListener(AssertListener listener) {
listeners.add(listener);
}
public void removeAssertEqualsListener(AssertListener listener) {
listeners.remove(listener);
}
@Override
public void addTo(ConcordionExtender concordionExtender) {
concordionExtender.withCommand("urn:error-extension:2017", "isError", new AbstractCommand() {
@Override
public void verify(CommandCall commandCall, Evaluator evaluator, ResultRecorder resultRecorder) {
Check.isFalse(commandCall.hasChildCommands(), "Nesting commands inside an 'isError' is not supported");
Element element = commandCall.getElement();
String actual = (String) evaluator.evaluate(commandCall.getExpression());
if (actual.contains("ERROR")) {
resultRecorder.record(Result.SUCCESS);
announceSuccess(element);
} else {
resultRecorder.record(Result.FAILURE);
announceFailure(element, "String containing ERROR", actual);
}
}
});
listeners.add(new AssertResultRenderer());
}
private void announceSuccess(Element element) {
for (AssertListener listener : listeners) {
listener.successReported(new AssertSuccessEvent(element));
}
}
private void announceFailure(Element element, String expected, Object actual) {
for (AssertListener listener : listeners) {
listener.failureReported(new AssertFailureEvent(element, expected, actual));
}
}
}
还显示 "best" 错误消息:
如我所见,Concordion 测试框架仅进行精确 strings/numbers 匹配。
是否有任何解决方法来测试结果包含一些子字符串?
例如,我测试服务 returns 格式错误 ERROR 123
,测试应该对任何错误号都有效。
为了测试你的逻辑,你可以去 http://www.vogella.com/tutorials/Mockito/article.html
根据所需的输出可读性和您要投入的工作量,有多种答案。
1) 最简单的是使用assert-true
来检查子字符串,例如:
The service [returns](- "#result=callService()") an [ERROR](- "c:assert-true=containsSubstring(#result, #TEXT)")
夹具:
@RunWith(ConcordionRunner.class)
public class Whosebug {
public String callService() {
// call your service here
}
public boolean containsSubstring(String input, String check) {
return input.contains(check);
}
}
这样做的缺点是,如果失败,错误消息只会显示:
2) 与 1 相同的夹具,containsSubstring
在失败时抛出异常。然后 Concordion 会将失败显示为堆栈跟踪:
public boolean containsSubstring(String input, String check) {
if (!input.contains(check)) {
throw new AssertionError("'" + input + "' does not contain '" + check + "'");
}
return true;
}
失败时显示:
3) 使用assertEquals
检查:
The service [returns](- "#result=callService()") an [ERROR](- "?=contains(#result, #TEXT)")
夹具:
public String contains(String input, String check) {
if (!input.contains(check)) {
return input;
}
return check;
}
这显示 "best" 错误消息:
4) 你可以写一个扩展,这样你就不用在每个装置中定义这样一个 contains
方法(或者从一个超类装置中继承它们):
规格:
The service [returns](- "#result=callService()") an [ERROR](- "cx:isError=#result")
夹具:
@RunWith(ConcordionRunner.class)
@ConcordionOptions(declareNamespaces={"cx", "urn:error-extension:2017"})
@Extensions(ErrorExtension.class)
public class Whosebug {
public String callService() {
// call your service here
}
}
分机:
public class ErrorExtension implements ConcordionExtension {
private List<AssertListener> listeners = new ArrayList<AssertListener>();
public void addAssertEqualsListener(AssertListener listener) {
listeners.add(listener);
}
public void removeAssertEqualsListener(AssertListener listener) {
listeners.remove(listener);
}
@Override
public void addTo(ConcordionExtender concordionExtender) {
concordionExtender.withCommand("urn:error-extension:2017", "isError", new AbstractCommand() {
@Override
public void verify(CommandCall commandCall, Evaluator evaluator, ResultRecorder resultRecorder) {
Check.isFalse(commandCall.hasChildCommands(), "Nesting commands inside an 'isError' is not supported");
Element element = commandCall.getElement();
String actual = (String) evaluator.evaluate(commandCall.getExpression());
if (actual.contains("ERROR")) {
resultRecorder.record(Result.SUCCESS);
announceSuccess(element);
} else {
resultRecorder.record(Result.FAILURE);
announceFailure(element, "String containing ERROR", actual);
}
}
});
listeners.add(new AssertResultRenderer());
}
private void announceSuccess(Element element) {
for (AssertListener listener : listeners) {
listener.successReported(new AssertSuccessEvent(element));
}
}
private void announceFailure(Element element, String expected, Object actual) {
for (AssertListener listener : listeners) {
listener.failureReported(new AssertFailureEvent(element, expected, actual));
}
}
}
还显示 "best" 错误消息: