Scalatestplus scalacheck 用于测试具有效果的 API,需要使用 unsafeRunSync()。

huangapple go评论47阅读模式
英文:

Scalatestplus scalacheck for testing effectful api requires unsafeRunSync()

问题

我正在探索实现对具有效果的 API 进行测试的选项为了简洁起见我有以下 API
```scala
object util {
  import cats.effect.Sync

  def stringReverser(string: String): String            = string.reverse
  def stringReverserF[F[_]: Sync](s: String): F[String] = Sync[F].delay(s.reverse)
}

我使用 AsyncWordSpec with ScalaCheckPropertyChecks。我不得不使用 unsafeRunSync

class SampleAsyncWordSpec extends wordspec.AnyWordSpec
      with org.scalatestplus.scalacheck.ScalaCheckPropertyChecks {

  import util._
  import cats.effect.unsafe.implicits.global
  "String reverser[F] with property based tests" must {
    "satisfy consistency with length in original and reversed string" in {
      forAll {(s: String) =>
        val ioAssertion  = stringReverserF[IO](s).map(r => assert(s.length() == r.length() + 1))
        ioAssertion.unsafeRunSync()
      }
    }
  }
}

是否有一种方法可以避免调用 unsafeRunSync() 并将其留给框架。在 scalatestplus 中与 scalacheck 一起使用时,并没有提到测试具有效果的 API。

PS:
这是我目标的一个简化示例。我正在探讨编写针对 tagless final algebra 的规则的选项。


<details>
<summary>英文:</summary>

I am exploring options to implement tests for effectful api. For brevity, I have the following api.
```scala
object util {
  import cats.effect.Sync

  def stringReverser(string: String): String            = string.reverse
  def stringReverserF[F[_]: Sync](s: String): F[String] = Sync[F].delay(s.reverse)

}

I use AsyncWordSpec with ScalaCheckPropertyChecks. I had to use unsafeRunSync.


class SampleAsyncWordSpec extends wordspec.AnyWordSpec  
      with org.scalatestplus.scalacheck.ScalaCheckPropertyChecks {

  import util._
  import cats.effect.unsafe.implicits.global
  &quot;String reverser[F] with property based tests&quot; must {
    &quot;satisfy consistency with length in original and reversed string&quot; in {
      forAll {(s: String) =&gt; 
        val ioAssertion  = stringReverserF[IO](s).map(r =&gt; assert(s.length() == r.length() + 1))  
        ioAssertion.unsafeRunSync()
      }
    }
  }

}

Is there a way to avoid calling unsafeRunSync() and leave it to the framework. In scalatestplus with scalacheck, there is no mention of testing effectful api.

PS:
This is a trimmed down example of my goal. I am exploring on options to write rules for tagless final algebra.

答案1

得分: 1

ScalaTest 本身并不是设计用于测试效果。

如果你查看 cats-effects testing 的官方文档,那里列出了你可以使用的不同库。你可以使用 cats-effect-testing,它可以与 ScalaTestscalacheck 集成。你还可以使用 scalacheck-effect,它也支持以 A =&gt; F[Assertion] 的形式编写具有效果的属性。

此外,如果你查看 cats-effect - testing # best practices,它说:

> 避免在测试中使用 unsafe* 方法,就像你在“主”代码中避免使用它们一样。编写与“正常”代码结构相同的测试会使测试不太可能出现故障,作为可执行文档,并保持易于阅读。

> 使用兼容的框架支持编写 IO[Assertion] 样式的测试。

所以,你在你写的示例测试中所做的并不完全是一个好的做法。

英文:

ScalaTest by itself, is not design for testing effects.

If you check the official docs of cats-effects testing, there is a list with the different libs that you can use. You have cats-effect-testing which can be integrated with ScalaTest and scalacheck. You have scalacheck-effect too that adds support for writing effectful properties with the shape A =&gt; F[Assertion].

Also if you check cats-effect - testing # best practices it says

> Avoid using unsafe* methods in tests, the same as you'd avoid them in
> "main" code. Writing tests to be structured the same way as "normal"
> code results in tests that are less likely to be flaky, act as
> executable documentation, and remain easy to read.
>
> Use a compatible framework's support for writing IO[Assertion] style
> tests.

So, what you are doing in the test you wrote as an example, it's not exactly good

答案2

得分: 1

如其他人已经回答,当使用scalatest与scalacheck时,无法避免这个问题。

但是,如果完全迁移不可行,没有什么可以阻止你在代码库中使用多个测试框架。

我建议使用scalacheck-effect与munit集成。我以前已成功将scalacheck和munit混合在同一个代码库中,原因类似 - sbt test 将运行它们全部。你也可以尝试编写一个与scalacheck-effect类似于munit的scalatest集成,但老实说我不会费心去做这件事。

通常,我还建议出于其他原因使用munit,如果迁移测试是一个选项,你应该考虑一下。根据你使用的scalatest DSL,这并不像你想象的那么困难。

英文:

As others have answered, when using scalatest with scalacheck, it's not possible to avoid this.

However, there's nothing stopping you from having multiple test frameworks in your codebase if a full migration isn't possible.

I recommend using scalacheck-effect with the munit integration. I've successfully mixed scalacheck+munit in the same codebase before for similar reasons - sbt test will run them all. It's possible that you could write a scalatest integration for scalacheck-effect similar to the munit one, but I wouldn't bother honestly.

I typically also recommend using munit over scalatest for other reasons; if it's an option to migrate your tests, you should consider it. It's not as hard as you might think, depending what scalatest DSL you're using

huangapple
  • 本文由 发表于 2023年6月5日 14:33:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76403996.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定