Java 用于断言实现的表达式的字符串表示形式
由于Java的Java 用于断言实现的表达式的字符串表示形式,java,android,assert,Java,Android,Assert,由于Java的assert关键字在Android上,因此我将实现一个断言类,该类也可以配置为在发布版本中检查断言 现在我可以做一些类似的事情: MyAssertion.assert(a != 2) 当表达式为false时,它抛出一个断言异常。但是如何获取表达式的字符串表示形式以传递到错误消息?唯一的方法是向assert方法添加字符串参数: MyAssertion.assert(a != 2, "a must not be equal to 2"); 作为assert的输入,您得到的是true
assert
关键字在Android上,因此我将实现一个断言类,该类也可以配置为在发布版本中检查断言
现在我可以做一些类似的事情:
MyAssertion.assert(a != 2)
当表达式为false时,它抛出一个断言异常。但是如何获取表达式的字符串表示形式以传递到错误消息?唯一的方法是向
assert
方法添加字符串参数:
MyAssertion.assert(a != 2, "a must not be equal to 2");
作为assert
的输入,您得到的是true或false,因此您无法从中构建代表性字符串
否则,您可以像这样实现assert
:
MyAssertion.assertNotEquals(a, 2);
当这失败时,您知道这是因为您测试的值等于2,并且您可以构建一条信息性消息(尽管您不知道具体什么值等于2)
如果您希望以某种方式从断言中构造有意义的消息,我认为唯一可行的方法就是构造一个字符串表达式,让JavaScript引擎对其求值,并在表达式求值为
false
时生成一条消息。请注意,这会降低很多性能,因为启动JavaScript引擎需要很多时间。这可以通过在生产中禁用断言的机制来解决
下面是一个例子。注意,我使用的是新的Java8NashornJavaScript引擎,但这应该适用于旧的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);
这将抛出第三个断言:
断言失败:3==4&&“测试”==“测试”
其思想是,您可以编写任何JavaScript友好的表达式,这些表达式可以计算为布尔值。占位符$i
将替换为方法的参数($1
将替换为第一个参数,以此类推)
这是一节课。它可以改进(处理错误情况,如参数不足等),但这应该足以让您开始
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();
}
}
公共最终类断言{
私有静态最终ScriptEngine引擎=新ScriptEngineManager().getEngineByName(“nashorn”);
私有断言(){}
公共静态void assertTrue(字符串表达式、对象…值){
对于(int i=0;i
(1)使用简单,但难以实现。需要Java8。可以使用lambda表达式:
Assert.isTrue(() => a != 2)
在评估失败时,您的Assert.isTrue方法的实现应该重复IDE所做的所有步骤—(a)发现lambda类的字节码,(b)反编译,例如使用JAD,(c)发现源代码(如果可用)
(2) 易于使用,易于实现,但不能完全满足您的需求。您可以使用代码样式规则检查并强制使用正确的断言。一个regexp将检查没有单参数断言,第二个(使用regexp back refs)将检查代码和文本描述是否相似
(3) 易于使用,易于实现,但依赖于构建系统。您可以在项目构建期间自动检查和修复源代码
例如,对于Maven build system,您可以创建自己的插件来检查和修复process sources阶段上源代码中的断言使用情况。我认为您无法访问传递给方法调用的内部java表达式 但是,您可以使用一些表达式语言库,并为断言实现执行自定义表达式处理 以下是一些表达式语言库的列表:
希望有帮助:)注释处理可以做到这一点。您需要创建一个注释,例如
@InlineAssertExpressions
。然后编写一个处理器,解析源文件并创建一个表示表达式的字符串,并将其添加到对assert方法的调用中,您可以重载该方法以获取可选的字符串参数。这种方式在性能方面是非常优化的,因为内联发生在编译时。注释处理有点被忽略了,但我认为这是一个很好的用途。assertEquals
和assertNotEquals
可能是基本表达式的解决方案。您能解释什么是根本性的问题,或者至少提供一个链接吗?@Axel,当然。添加了一个源代码。只是一个建议,因为您正在开始一些新的东西-看看Guava的先决条件。有没有理由不使用jUnit对您的发布进行单元测试?否则,断言通常只是生产代码中的错误实践。谢谢您的回答。这两种方法都是我不想做的妥协:第一种方法需要源代码中的冗余信息。每当我改变等式时,我都需要注意使文本适应它。编写琐碎的文本也无益于浪费开发人员的时间。第二种方法要求对所有类型的方程采用不同的方法,这种方法不酷,但可以接受。更大的问题是可读性:a==2
vs.a!=2
或a!=null
比不同的断言函数名更容易阅读。不过,谢谢你。这可能是我能做的最好的了