由于 Java 的 assert
关键字是 fundamentally broken在 Android 上,我将要实现一个断言类,该类也可以配置为检查发布版本中的断言。
现在我可以做类似的事情:
MyAssertion.assert(a != 2)
当表达式为假时抛出 AssertionException
。但是我怎样才能得到表达式的字符串表示形式以传递给错误消息呢?
最佳答案
唯一的方法是在 assert
方法中添加一个字符串参数:
MyAssertion.assert(a != 2, "a must not be equal to 2");
你得到的 assert
的输入要么是真要么是假,所以你不能从中构建一个有代表性的字符串。
否则,您可以像这样实现 assert
:
MyAssertion.assertNotEquals(a, 2);
当失败时,您知道这是因为您测试的值等于 2,并且您可以构建一条信息性消息(尽管您不知 Prop 体等于 2 的是什么)。
如果你想以某种方式能够从一个断言中构建一个有意义的消息,我认为唯一可能的方法是构建一个字符串表达式,让 JavaScript 引擎对其求值并在表达式求值为 false
时构建一条消息.请注意,这会降低很多性能,因为启动 JavaScript 引擎需要很长时间。这可以通过在生产中禁用断言的机制来解决。
下面是一个例子。请注意,我使用的是新的 Java 8 Nashorn JavaScript 引擎,但这应该适用于旧版 Rhino。
使用示例:
int value = 3;
String str = "test";
Assertions.assertTrue("$1 == 3", value);
Assertions.assertTrue("$1 == 3 && $2 == 'test'", value, str);
Assertions.assertTrue("$1 == 4 && $2 == 'test'", value, str);
这将抛出第三个断言:
An assertion has failed: 3 == 4 && 'test' == 'test'
这个想法是您可以编写任何可以计算为 boolean 值的 JavaScript 友好表达式。占位符 $i
将替换为方法的参数($1
将替换为第一个参数,等等)。
这是类(class)。它可以改进(处理错误情况,例如参数不足等),但这应该足以让您入门。
public final class Assertions {
private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("nashorn");
private Assertions() { }
public static void assertTrue(String expression, Object... values) {
for (int i = 0; i < values.length; i++) {
ENGINE.put("$" + (i+1), values[i]);
}
try {
boolean pass = (Boolean) ENGINE.eval(expression);
if (!pass) {
for (int i = 0; i < values.length; i++) {
expression = expression.replace("$" + (i+1), stringRepresentation(values[i]));
}
throw new AssertionError("An assertion has failed: " + expression);
}
} catch (ScriptException e) {
throw new InternalError(e);
} finally {
for (int i = 0; i < values.length; i++) {
ENGINE.getBindings(ScriptContext.ENGINE_SCOPE).remove("$" + (i+1));
}
}
}
private static String stringRepresentation(Object o) {
if (o instanceof String) {
return "'" + o + "'";
}
return o.toString();
}
}
关于java - 用于断言实现的表达式的字符串表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32756683/