以模块化方式创建 Specs2 匹配器
我有函数 A =>;双倍
。我想检查两个这样的函数对于给定的一组值是否给出相同的结果(在容差范围内,使用现有的 beCloseTo 匹配器)。
我希望能够写:
type TF = A => Double
(f: TF) must computeSameResultsAs(g: TF,tolerance: Double, tests: Set[A])
我想以模块化的方式构建这个匹配器,而不是简单地从头开始编写 Matcher[TF]
。
如果我可以写的话可能会更好:
(f: TF) must computeSameResultsAs(g: TF)
.withTolerance(tolerance)
.onValues(tests: Set[A])
另外,我想在匹配器失败时得到合理的描述。
编辑
睡了一觉后,我想出了以下内容。
def computeSameResultsAs[A](ref: A => Double, tolerance: Double, args: Set[A]): Matcher[A => Double] =
args.map(beCloseOnArg(ref, tolerance, _)).reduce(_ and _)
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg))
这比 Eric 的解决方案短得多,但没有提供良好的失败消息。我希望能够在第二种方法中重命名映射值。类似于以下内容(无法编译)。
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg) aka "result on argument " + arg)
I have functions A => Double
. I want to check whether two such functions give the same results (up to a tolerance, using the existing beCloseTo
matcher) for a given set of values.
I want to be able to write:
type TF = A => Double
(f: TF) must computeSameResultsAs(g: TF,tolerance: Double, tests: Set[A])
I want to build this matcher in a modular way, not simply writing a Matcher[TF]
from scratch.
It might be even nicer if I could write:
(f: TF) must computeSameResultsAs(g: TF)
.withTolerance(tolerance)
.onValues(tests: Set[A])
Also I want to get a reasonable description when the matcher fails.
Edit
After sleeping over it I came up with the following.
def computeSameResultsAs[A](ref: A => Double, tolerance: Double, args: Set[A]): Matcher[A => Double] =
args.map(beCloseOnArg(ref, tolerance, _)).reduce(_ and _)
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg))
This is much shorter than Eric's solution but doesn't provide a good failure message. What I'd love to be able is rename the mapped value in the second method. Something like the following (which does not compile).
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg) aka "result on argument " + arg)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您想使用第二个版本编写内容,则需要创建一个新的
Matcher
类来封装beCloseTo
匹配器的功能:此类允许使用您正在使用的语法之后:
现在,让我们看看如何在
apply
方法中重用beCloseTo
匹配器:在上面的代码中,我们应用了一个返回
MatcherResult
的函数<一href="http://etorreborre.github.com/specs2/guide/org.specs2.guide.Matchers.html#Matching+with+a+sequence+of+values" rel="noreferrer">到一系列值:请注意:
f
是一个Expectable[A =>; Double]
因此我们需要获取其实际的值
才能使用它同样,我们只能将
Expectable[T]
应用于< code>Matcher[T] 因此我们需要使用theValue
方法将f.value(v)
转换为Expectable[Double]< /代码>(来自
MustExpectations
特征)最后,我们得到的结果是
对于所有
匹配,我们可以使用以下方法自定义结果消息:继承的
result
方法构建MatchResult
(应用的内容任何
方法都应该返回Matcher
的向其传递一个布尔值,表示
beCloseTo
的执行是否成功:.isSuccess
根据输入和
beCloseTo
的输入和结果消息,传递格式良好的“ok”和“ko”消息>匹配向其传递
Expectable
code> 最初用于进行匹配:f
,因此最终结果的类型为MatchResult[A =>; Double]
我不确定根据您的要求我们可以得到多少模块化。在我看来,我们在这里能做的最好的事情就是重用
beCloseTo
和forall
。更新
一个较短的答案可能是这样的:
上面的代码创建了一条失败消息,例如:
这应该几乎可以开箱即用。缺少的部分是从
A => 的隐式转换。 MatchResult[_]
到Matcher[A]
(我将添加到下一个版本中):您可以使用
foreach
而不是forall
如果你想获得所有失败:UPDATE 2
这每天都会变得更好。使用最新的specs2快照,您可以编写:
更新3
现在,使用最新的specs2快照,您可以编写:
失败消息将是:
If you want to write things with the second version you need to create a new
Matcher
class encapsulating the functionality of thebeCloseTo
matcher:This class allows to use the syntax you're after:
Now, let's see how to reuse the
beCloseTo
matcher in theapply
method:In the code above, we apply a function returning a
MatcherResult
to a sequence of values:Note that:
f
is anExpectable[A => Double]
so we need to take its actualvalue
to be able to use itsimilarly we can only apply an
Expectable[T]
to aMatcher[T]
so we need to use the methodtheValue
to transformf.value(v)
to anExpectable[Double]
(from theMustExpectations
trait)Finally, we when have the result of the
forall
matching, we can customize the result messages by using:the inherited
result
method building aMatchResult
(what theapply
method of anyMatcher
should returnpassing it a boolean saying if the execution of
beCloseTo
was successful:.isSuccess
passing it nicely formatted "ok" and "ko" messages, based on the input and on the result message of the
beCloseTo
matchingpassing it the
Expectable
which was used to do the matching in the first place:f
, so that the final result has a type ofMatchResult[A => Double]
I'm not sure how more modular we can get given your requirements. It looks to me that the best we can do here is to reuse
beCloseTo
withforall
.UPDATE
A shorter answer might be something like this:
The code above creates a failure message like:
This should almost work out-of-the-box. The missing part is an implicit conversion from
A => MatchResult[_]
toMatcher[A]
(which I'm going to add to the next version):You can use
foreach
instead offorall
if you want to get all the failures:UPDATE 2
This gets better everyday. With the latest specs2 snapshot you can write:
UPDATE 3
And now with the latest specs2 snapshot you can write:
The failure message will be: