{"id":308846,"date":"2020-08-21T21:00:20","date_gmt":"2020-08-21T21:00:20","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=308846"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=308846","title":{"rendered":"\u0418\u0437\u0443\u0447\u0430\u044e Scala: \u0427\u0430\u0441\u0442\u044c 3 \u2014 \u042e\u043d\u0438\u0442 \u0422\u0435\u0441\u0442\u044b"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/516154\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zo\/xd\/gp\/zoxdgp56ikqqru3y8va_jqtaz0i.png\"><\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u0430\u043b\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u043a\u043e\u0434. \u041d\u0443\u0436\u043d\u043e \u0435\u0449\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0435\u0433\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u043c\u0438 \u042e\u043d\u0438\u0442 \u0422\u0435\u0441\u0442\u0430\u043c\u0438. \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0435\u0440. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u044e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432. \u041e\u0431\u044b\u0447\u043d\u044b\u0445, Property-based \u0438 \u0441 \u043c\u043e\u043a\u0430\u043c\u0438. \u0417\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/503560\/\">\u0418\u0437\u0443\u0447\u0430\u044e Scala: \u0427\u0430\u0441\u0442\u044c 1 \u2014 \u0418\u0433\u0440\u0430 \u0437\u043c\u0435\u0439\u043a\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/508560\/\">\u0418\u0437\u0443\u0447\u0430\u044e Scala: \u0427\u0430\u0441\u0442\u044c 2 \u2014 Todo \u043b\u0438\u0441\u0442 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a<\/a><\/li>\n<li>\u0418\u0437\u0443\u0447\u0430\u044e Scala: \u0427\u0430\u0441\u0442\u044c 3 \u2014 \u042e\u043d\u0438\u0442 \u0422\u0435\u0441\u0442\u044b<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u0421\u0441\u044b\u043b\u043a\u0438<\/h2>\n<p>  <a href=\"https:\/\/gitlab.com\/VictorWinbringer\/scalatodoapi\" rel=\"nofollow\">\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438<\/a><br \/>  <a href=\"https:\/\/gitlab.com\/VictorWinbringer\/scalatodoapi\/container_registry\/\" rel=\"nofollow\">\u041e\u0431\u0440\u0430\u0437\u044b docker image<\/a><\/p>\n<p>  \u0418 \u0442\u0430\u043a \u0434\u043b\u044f \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0443\u0436\u043d\u044b 3 \u043b\u0438\u0431\u044b.<\/p>\n<ol>\n<li>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/li>\n<li>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435<\/li>\n<li>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u043e\u043a\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432<\/li>\n<\/ol>\n<p>  \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/scalatest\/scalatest\" rel=\"nofollow\">ScalaTest<\/a> <\/p>\n<pre><code class=\"scala\">&quot;org.scalatest&quot; %% &quot;scalatest&quot; % &quot;3.2.0&quot; % Test <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f Property-based \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a href=\"https:\/\/github.com\/typelevel\/scalacheck\" rel=\"nofollow\">ScalaCheck<\/a><\/p>\n<pre><code class=\"scala\">&quot;org.scalacheck&quot; %% &quot;scalacheck&quot; % &quot;1.14.3&quot; % Test <\/code><\/pre>\n<p>  \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0435\u0442 ScalaTest + ScalaCheck <a href=\"https:\/\/github.com\/scalatest\/scalatestplus-scalacheck\" rel=\"nofollow\">ScalaTestPlusScalaCheck<\/a><\/p>\n<pre><code class=\"scala\">&quot;org.scalatestplus&quot; %% &quot;scalacheck-1-14&quot; % &quot;3.2.0.0&quot; % Test <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u043e\u043a\u043e\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a href=\"https:\/\/github.com\/paulbutcher\/ScalaMock\" rel=\"nofollow\">ScalaMock<\/a><\/p>\n<pre><code class=\"scala\">&quot;org.scalamock&quot; %% &quot;scalamock&quot; % &quot;4.4.0&quot; % Test <\/code><\/pre>\n<p>  \u041f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0442\u0438\u043f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 (\u043d\u0435 \u043f\u0443\u0441\u0442\u043e\u0439) \u0441\u0442\u0440\u043e\u043a\u0438. \u0415\u0433\u043e \u043c\u044b \u0441\u0435\u0439\u0447\u0430\u0441 \u0438 \u0431\u0443\u0434\u0435\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. <\/p>\n<pre><code class=\"scala\">package domain.common  sealed abstract case class FilledStr private(value: String)  object FilledStr {   def apply(value: String): Option[FilledStr] = {     val trimmed = value.trim     if (trimmed.nonEmpty) {       Some(new FilledStr(trimmed) {})     } else {       None     }   } } <\/code><\/pre>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 <\/p>\n<pre><code class=\"scala\">class FilledStrTests extends AnyFlatSpec with should.Matchers with ScalaCheckPropertyChecks {  } <\/code><\/pre>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0447\u0442\u043e \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0438\u0437 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. <\/p>\n<pre><code class=\"scala\"> &quot;equals&quot; should &quot;return true fro equal value&quot; in {     val str = &quot;1234AB&quot;     val a = FilledStr(str).get     val b = FilledStr(str).get     b.equals(a) should be(true)   } <\/code><\/pre>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043c\u044b \u0437\u0430\u0445\u0440\u0430\u0434\u043a\u043e\u0434\u0438\u043b\u0438 \u0432 \u0440\u0443\u0447\u043d\u0443\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443. \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0435\u0441\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c property-based \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0447\u0442\u043e \u043f\u0440\u0438 \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u0435 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. <\/p>\n<pre><code class=\"scala\">  &quot;constructor&quot; should &quot;save expected value&quot; in {     forAll { s: String =&gt; \/\/\u0422\u0443\u0442 \u0444\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0413\u043e\u0432\u043e\u0440\u0438\u043c \u0447\u0442\u043e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438.       whenever(s.trim.nonEmpty) {         val a = FilledStr(s).get         a.value should be(s)       }     }   } <\/code><\/pre>\n<p>  \u041c\u043e\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"scala\">\/\/\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0430\u0448 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 val evenInts = for (n &lt;- Gen.choose(-1000, 1000)) yield 2 * n \/\/\u041f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0441 \u044d\u0442\u0438\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c forAll (evenInts) { (n) =&gt; n % 2 should equal (0) } <\/code><\/pre>\n<p>  \u0422\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u044f\u0432\u043d\u043e \u043d\u0430\u0448 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0435\u0433\u043e implict \u0447\u0435\u0440\u0435\u0437 Arbitrary \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0432 \u0442\u0435\u0441\u0442\u044b. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"scala\">implicit lazy val myCharArbitrary = Arbitrary(Gen.oneOf('A', 'E', 'I', 'O', 'U')) val validChars: Seq[Char] = List('X') \/\/\u042d\u0442\u043e \u0442\u0435\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043a\u0430\u0442\u044c \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 Arbitrary[Char] \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0438\u0437 \u043d\u0435\u0433\u043e. forAll { c: Char =&gt; validChars.contains(c) } <\/code><\/pre>\n<p>  \u0422\u0430\u043a \u0436\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Arbitrary \u043c\u043e\u0436\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b.<\/p>\n<pre><code class=\"scala\">case class Foo(intValue: Int, charValue: Char)  val fooGen = for {   intValue &lt;- Gen.posNum[Int]   charValue &lt;- Gen.alphaChar } yield Foo(intValue, charValue)  implicit lazy val myFooArbitrary = Arbitrary(fooGen)  forAll { foo: Foo =&gt; (foo.intValue &lt; 0) ==  &amp;&amp; !foo.charValue.isDigit } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442 \u043f\u043e \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u0435\u0439. \u0411\u0443\u0434\u0435\u043c \u043c\u043e\u043a\u0430\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f TodosService. \u041e\u043d \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 2 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044e \u043d\u0430\u0434 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0435\u0439 UnitOfWork. \u0411\u0443\u0434\u0435\u043c \u0442\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043c\u0435\u0442\u043e\u0434<\/p>\n<pre><code class=\"scala\">  def getAll(): F[List[Todo]] =     repo.getAll().commit() <\/code><\/pre>\n<p>  \u041a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432 \u043d\u0435\u043c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 Todo, \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442 \u0435\u0435 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u0422\u0430\u043a \u0436\u0435 \u0432 \u0442\u0435\u0441\u0442\u0435 \u0432\u043c\u0435\u0441\u0442\u043e F[_] \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043c\u043e\u043d\u0430\u0434\u0430 Id \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0445\u0440\u0430\u043d\u044f\u0449\u0435\u0435\u0441\u044f \u0432 \u043d\u0435\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435.<\/p>\n<pre><code class=\"scala\">class TodoServiceTests extends AnyFlatSpec with MockFactory with should.Matchers {   &quot;geAll&quot; should &quot;\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f&quot; in { \/\/\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u043e\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.     implicit val tr = mock[TodosRepositoryContract[Id, Id]]     implicit val ir = mock[InstantsRepositoryContract[Id]]     implicit val uow = mock[UnitOfWorkContract[Id, List[Todo], Id]] \/\/\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441. \u041e\u043d \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0441\u0432\u043e\u0439 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043d\u0435 \u044f\u0432\u043d\u043e \u0447\u0435\u0440\u0435\u0437 implicit     val service= new TodosService[Id, Id]() \/\/\u0421\u043e\u0437\u0434\u0430\u0435\u043c Id \u043c\u043e\u043d\u0430\u0434\u0443 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c Todo \u0432\u043d\u0443\u0442\u0440\u0438     val list: Id[List[Todo]] = List(Todo(1, &quot;2&quot;, 3, Instant.now())) \/\/\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 getAll \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c uow \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d 1 \u0440\u0430\u0437     (tr.getAll _).expects().returning(uow).once() \/\/\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 commit \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d 1 \u0440\u0430\u0437     (uow.commit _).expects().returning(list).once() \/\/\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0447\u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 getAll \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0440\u0430\u0432\u0435\u043d \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438  \/\/\u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u0430\u0448 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439     service.getAll() should be(list)   } } <\/code><\/pre>\n<p>  \u0422\u0435\u0441\u0442\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 Scala \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u0434\u0430\u0436\u0435 \u043f\u0440\u0438\u044f\u0442\u043d\u043e \u0438 ScalaCheck, ScalaTest, ScalaMock \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u0438\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438. \u041a\u0430\u043a \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0410\u041f\u0418 tapir \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 http4s \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0438\u043c\u043e\u0432 fs2. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f Scala \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0443 \u043c\u0435\u043d\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u044d\u043c\u043e\u0446\u0438\u0438. \u041d\u0430\u0434\u0435\u044e\u0441\u044c \u0434\u0430\u043b\u044c\u0448\u0435 \u044d\u0442\u0430 \u0442\u0435\u043d\u0434\u0435\u043d\u0446\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0441\u044f.<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/516154\/\"> https:\/\/habr.com\/ru\/post\/516154\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/516154\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zo\/xd\/gp\/zoxdgp56ikqqru3y8va_jqtaz0i.png\"><\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u0430\u043b\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u043a\u043e\u0434. \u041d\u0443\u0436\u043d\u043e \u0435\u0449\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0435\u0433\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u043c\u0438 \u042e\u043d\u0438\u0442 \u0422\u0435\u0441\u0442\u0430\u043c\u0438. \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0435\u0440. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u044e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432. \u041e\u0431\u044b\u0447\u043d\u044b\u0445, Property-based \u0438 \u0441 \u043c\u043e\u043a\u0430\u043c\u0438. \u0417\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-308846","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308846","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=308846"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308846\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=308846"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=308846"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=308846"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}