As i see, Concordion test framework makes only exact strings/numbers matching.
Is there any workaround to test the result contains some substring?
For instance, i test a service returns an error in format ERROR 123
, and the test should be valid for any error number.
There's a number of answers depending on the desired readability of the output and the amount of effort you want to put in.
1) Easiest is to use assert-true
to check for the substring, eg:
The service [returns](- "#result=callService()") an [ERROR](- "c:assert-true=containsSubstring(#result, #TEXT)")
with fixture:
@RunWith(ConcordionRunner.class)
public class StackOverflow {
public String callService() {
// call your service here
}
public boolean containsSubstring(String input, String check) {
return input.contains(check);
}
}
The downside of this is that, on failure, the error message will just show:
2) Same fixture as 1, with containsSubstring
throwing an exception on failure. Concordion would then show the failure as a stack trace:
public boolean containsSubstring(String input, String check) {
if (!input.contains(check)) {
throw new AssertionError("'" + input + "' does not contain '" + check + "'");
}
return true;
}
On failure this shows:
3) Use assertEquals
to check:
The service [returns](- "#result=callService()") an [ERROR](- "?=contains(#result, #TEXT)")
with fixture:
public String contains(String input, String check) {
if (!input.contains(check)) {
return input;
}
return check;
}
This shows the "best" error message:
4) You could write an extension, which would save you from defining such a contains
method in every fixture (or inheriting them all from one superclass fixture):
Spec:
The service [returns](- "#result=callService()") an [ERROR](- "cx:isError=#result")
Fixture:
@RunWith(ConcordionRunner.class)
@ConcordionOptions(declareNamespaces={"cx", "urn:error-extension:2017"})
@Extensions(ErrorExtension.class)
public class StackOverflow {
public String callService() {
// call your service here
}
}
Extension:
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));
}
}
}