加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 测试副作用monad的定律

发布时间:2020-12-16 19:16:42 所属栏目:安全 来源:网络整理
导读:我正在编写一个库来通过API访问Web服务.我已经定义了简单的类来表示API动作 case class ApiAction[A](run: Credentials = Either[Error,A]) 和一些执行Web服务调用的函数 // Retrieve foo by iddef get(id: Long): ApiAction[Foo] = ???// List all foo'sdef
我正在编写一个库来通过API访问Web服务.我已经定义了简单的类来表示API动作

case class ApiAction[A](run: Credentials => Either[Error,A])

和一些执行Web服务调用的函数

// Retrieve foo by id
def get(id: Long): ApiAction[Foo] = ???

// List all foo's
def list: ApiAction[Seq[Foo]] = ???

// Create a new foo
def create(name: String): ApiAction[Foo] = ???

// Update foo
def update(updated: Foo): ApiAction[Foo] = ???

// Delete foo
def delete(id: Long): ApiAction[Unit] = ???

我也让ApiAction成为monad

implicit val monad = new Monad[ApiAction] { ... }

所以我可以做点什么

create("My foo").run(c)
get(42).map(changeFooSomehow).flatMap(update).run(c)
get(42).map(_.id).flatMap(delete).run(c)

现在我有麻烦测试它的monad法律

val x = 42
val unitX: ApiAction[Int] = Monad[ApiAction].point(x)

"ApiAction" should "satisfy identity law" in {
  Monad[ApiAction].monadLaw.rightIdentity(unitX) should be (true)
}

因为monadLaw.rightIdentity使用相同的

def rightIdentity[A](a: F[A])(implicit FA: Equal[F[A]]): Boolean = 
  FA.equal(bind(a)(point(_: A)),a)

而且没有平等[ApiAction].

[error] could not find implicit value for parameter FA: scalaz.Equal[ApiAction[Int]]
[error]     Monad[ApiAction].monadLaw.rightIdentity(unitX) should be (true)
[error]                                            ^

问题是我甚至无法想象如何定义Equal [ApiAction]. ApiAction本质上是一个函数,我不知道函数的任何相等关系.当然可以比较运行ApiAction的结果,但它不一样.

当我做一些非常错误的事情或者不理解某些必要的东西时,我觉得这样.所以我的问题是:

> ApiAction成为monad是否有意义?
>我设计了ApiAction吗?
>我应该如何测试其monad法律?

解决方法

我将从简单的开始:是的,ApiAction成为monad是有道理的.是的,你以合理的方式设计它 – 这个设计看起来有点像Haskell中的IO monad.

棘手的问题是你应该如何测试它.

有意义的唯一相等关系是“在给定相同输入的情况下产生相同的输出”,但这仅在纸上非常有用,因为计算机无法验证,并且它仅对纯函数有意义.实际上,Haskell的IO monad与你的monad有一些相似之处,并没有实现Eq.如果你没有实现Equal [ApiAction],那么你可能已经安全了.

尽管如此,可能还有一个论点是实现一个特殊的Equal [ApiAction]实例,仅用于测试,它使用硬编码的Credentials值(或少量硬编码值)运行操作并比较结果.从理论的角度来看,这很糟糕,但从实用的角度来看,它并不比使用测试用例进行测试更糟糕,并且允许您重用Scalaz中现有的帮助函数.

另一种方法是忘记Scalaz,证明ApiAction使用铅笔和纸来满足monad法则,并编写一些测试用例来验证一切都按照你的想法运行(使用你编写的方法,而不是来自Scalaz的人).实际上,大多数人都会跳过铅笔纸步骤.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读