我有一个扩展GeneratorDrivenPropertyChecks
的ScalaTest 2类,并间接扩展FeatureSpec
和Matchers
(通过我编写的扩展这两个类的特征)。它的代码如下:
forAll(mySequence) { myItem =>
myItem.applicationID should be (foo.applicationID)
}
这无法编译,因为scalac说:
[error] APISpec.scala:253: value applicationID is not a member of Seq[com.company.Item]
[error] myItem.applicationID should be (foo.applicationID)
[error] ^
事实证明,至少根据Eclipse Scala IDE,编译器在GeneratorDrivenpropertyChecks
中解析“forAll”意味着这个方法:
/**
* Performs a property check by applying the specified property check function to arguments
* supplied by the specified generators.
*
* <p>
* Here's an example:
* </p>
*
* <pre class="stHighlight">
* import org.scalacheck.Gen
*
* // Define your own string generator:
* val famousLastWords = for {
* s <- Gen.oneOf("the", "program", "compiles", "therefore", "it", "should", "work")
* } yield s
*
* forAll (famousLastWords) { (a: String) =>
* a.length should equal ((a).length)
* }
* </pre>
*
* @param fun the property check function to apply to the generated arguments
*/
def forAll[A](genA: Gen[A], configParams: PropertyCheckConfigParam*)(fun: (A) => Unit)
(implicit
config: PropertyCheckConfig,
shrA: Shrink[A]
) {
// body omitted
}
这不是我想在这里使用的forAll
方法!
这是ScalaTest中的错误(即两个方法都不应该都被命名为forAll
)?
我该如何调用正确的方法?
答案 0 :(得分:7)
这是ScalaTest中的错误
它演示了方法重载的限制。
在an article on selfless traits中,Bill Venners将此模式描述为这些命名冲突的解决方法。
在您的情况下,首选一个重载,因为它是在“派生类”中定义的。
(我认为;我不是这些测试框架的用户,并且生成了其中一个源,等等,所以测试这个并不是一个简单的事情就是启动sbt并查看代码。)
(编辑:scaladoc说你应该import Inspectors._
。也许你希望用Matchers
继承它,因为它也建议导入它的同伴,虽然这不起作用对我来说,如果你做了import Inspectors._
,你实际上不能通过导入名称来引起过载。)
(编辑:解释命名位:请参阅规范的第2章的开头,其中它表示名称的绑定具有优先权,并且您继承的名称优先于您导入的名称。)
无论如何,一个解决方案就是重新混入Inspectors
,如下所示。
另一种解决方案是使用重命名导入方法:
import Inspectors.{ forAll => iforAll }
尝试选项“-Xprint:typer”,“ - Xlog-implicit-conversions”以查看正在发生的事情非常有用。在您的情况下,ScalaCheck 1.10中的隐式视图Gen.value
会将您的集合提升为“常量gen”。
import org.scalatest._
import org.scalatest.prop._
//class MySpec extends FeatureSpec with Matchers with GeneratorDrivenPropertyChecks
class MySpec extends FeatureSpec with Matchers with GeneratorDrivenPropertyChecks with Inspectors {
case class Foo(id: Int)
val items = 1 to 10 map (Foo.apply(_))
forAll(items) { x => Console println x.id }
}
object Test extends App {
case class Foo(id: Int)
val items = 1 to 10 map (Foo.apply(_))
val sut = new MySpec
sut.forAll(items) { x => Console println x.id }
//sut.forAll[Foo](items) { x => Console println x.i }
}
一些调试输出:
/*
[info] /home/apm/projects/skala-unit-tests/src/test/scala/maqi/MySpec.scala:15: inferred view from scala.collection.immutable.IndexedSeq[maqi.Test.Foo] to org.scalacheck.Gen[?] = scalacheck.this.Gen.value[scala.collection.immutable.IndexedSeq[maqi.Test.Foo]]:(x: scala.collection.immutable.IndexedSeq[maqi.Test.Foo])org.scalacheck.Gen[scala.collection.immutable.IndexedSeq[maqi.Test.Foo]]
> test
[info] Compiling 3 Scala sources to /home/apm/projects/skala-unit-tests/target/scala-2.10/test-classes...
[error] /home/apm/projects/skala-unit-tests/src/test/scala/maqi/MySpec.scala:16: overloaded method value forAll with alternatives:
[error] (genAndNameA: (org.scalacheck.Gen[maqi.Test.Foo], String),configParams: maqi.Test.sut.PropertyCheckConfigParam*)(fun: maqi.Test.Foo => Unit)(implicit config: maqi.Test.sut.PropertyCheckConfig, implicit shrA: org.scalacheck.Shrink[maqi.Test.Foo])Unit <and>
[error] (genA: org.scalacheck.Gen[maqi.Test.Foo],configParams: maqi.Test.sut.PropertyCheckConfigParam*)(fun: maqi.Test.Foo => Unit)(implicit config: maqi.Test.sut.PropertyCheckConfig, implicit shrA: org.scalacheck.Shrink[maqi.Test.Foo])Unit <and>
[error] (nameA: String,configParams: maqi.Test.sut.PropertyCheckConfigParam*)(fun: maqi.Test.Foo => Unit)(implicit config: maqi.Test.sut.PropertyCheckConfig, implicit arbA: org.scalacheck.Arbitrary[maqi.Test.Foo], implicit shrA: org.scalacheck.Shrink[maqi.Test.Foo])Unit <and>
[error] (fun: maqi.Test.Foo => Unit)(implicit config: maqi.Test.sut.PropertyCheckConfig, implicit arbA: org.scalacheck.Arbitrary[maqi.Test.Foo], implicit shrA: org.scalacheck.Shrink[maqi.Test.Foo])Unit
[error] cannot be applied to (scala.collection.immutable.IndexedSeq[maqi.Test.Foo])
[error] sut.forAll[Foo](items) { x => Console println x.i }
[error] ^
*/