有没有办法编写像“单元测试”这样的东西来确保某些代码不编译?
为什么我想要这样的东西?有两个原因。
1)检查我的API的类型安全性。我想要一种方法来确保是否有人传入错误值,您会收到编译器错误,而不仅仅是运行时错误。显然,我可以运行编译器并检查错误,但在单元测试中将其形式化是有利于避免回归&也用于文档。
例如,考虑这个测试。我用过一些注释掉的代码来检查类型安全性: https://github.com/squito/boxwood/blob/master/core/src/test/scala/com/quantifind/boxwood/EnumUnionTest.scala#L42 (第42行和第48行 - 在第34行,我调用了一个不同的API,它有一个运行时异常,我可以检查)
实际上我需要一段时间来获得类型安全权,所以这些都是重要的检查。现在,如果我去修改底层实现,我不能只运行我的测试套件 - 我还要记得取消注释这些行并检查编译器错误。
2)测试宏的错误处理。如果宏有一些错误的输入,它应该导致编译器错误。同样的问题,同样希望在易于运行的测试套件中使用它。
我使用ScalaTest,但我很高兴能在这里找到任何单元测试框架的解决方案。
答案 0 :(得分:11)
正如我在上面的评论中指出的那样,基于Stefan Zeiger的解决方案,Shapeless 2.0(尚未发布但目前作为里程碑提供)具有您正在寻找的功能的非常好的实现。我已经为您的项目添加了一个演示here(请注意,我必须更新到Scala 2.10,因为此解决方案使用宏)。它的工作原理如下:
import shapeless.test.illTyped
//this version won't even compile
illTyped("getIdx(C.Ooga)")
//We can have multiple enum unions exist side by side
import Union_B_C._
B.values().foreach {b => Union_B_C.getIdx(b) should be (b.ordinal())}
C.values().foreach {c => Union_B_C.getIdx(c) should be (c.ordinal() + 2)}
//Though A exists in some union type, Union_B_C still doesn't know about it,
// so this won't compile
illTyped("""
A.values().foreach {a => Union_B_C.getIdx(a) should be (a.ordinal())}
""")
如果我们要将第二次调用illTyped
中的代码更改为将要编译的内容:
B.values().foreach {a => Union_B_C.getIdx(a) should be (a.ordinal())}
我们收到以下编译错误:
[error] .../EnumUnionTest.scala:56: Type-checking succeeded unexpectedly.
[error] Expected some error.
[error] illTyped("""
[error] ^
[error] one error found
[error] (core/test:compile) Compilation failed
如果你更喜欢测试失败,你很容易适应the implementation in Shapeless。有关额外讨论,请参阅Miles's answer至my previous question。
答案 1 :(得分:6)
Scalatest也可以这样做。
Checking that a snippet of code does not compile
通常在创建库时,您可能希望确保某些库 表示潜在“用户错误”的代码排列不会 编译,以便您的库更具错误性。 ScalaTest Matchers trait包含以下语法:
"val a: String = 1" shouldNot compile
如果你想确保一个 代码片段由于类型错误而无法编译(相反 语法错误),使用:
"val a: String = 1" shouldNot typeCheck
请注意,
shouldNot typeCheck
语法只有在给定代码片段的情况下才会成功 由于类型错误而无法编译。仍会出现语法错误 抛出TestFailedException
。如果你想声明一段代码确实编译,你可以做 更明显的是:
"val a: Int = 1" should compile
虽然前三个结构 用宏来实现,在编译时确定是否 由字符串表示的代码片段是否编译, 错误在运行时报告为测试失败。
答案 2 :(得分:0)
特拉维斯·布朗的回答绝对正确。为了完整起见,我想补充一点,这也适用于测试宏,如here所示。
一个小问题:illTyped
检查在repl中似乎不起作用。它永远不会抛出错误,即使给定的表达式进行类型检查。但是,不要让那个愚弄你,它确实运作良好。
> test:console
Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_65).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def foo(s: String) = s
foo: (s: String)String
scala> import shapeless.test.illTyped
import shapeless.test.illTyped
scala> foo(1)
<console>:10: error: type mismatch;
found : Int(1)
required: String
foo(1)
^
scala> illTyped("""foo(1)""")
scala> illTyped("""foo("hi there")""") // <--- works, but shouldn't!