ScalaCheckã«ã€ããŠ
ããŒã1.ã¯ããã«
ScalaCheckã¯ãScalaã§ã®åäœãã¹ãã®äœæãã¯ããã«ç°¡åã«ããçµã¿åããã©ã€ãã©ãªã§ãã Haskellèšèªçšã®QuickCheckã©ã€ãã©ãªã«æåã«å®è£ ãããããããã£ããŒã¹ã®ãã¹ãã¢ãããŒãã䜿çšããŸãã QuickCheckã«ã¯å€ãã®å®è£ ããããŸãïŒ Java ã C ãããã³ä»ã®èšèªãšãã©ãããã©ãŒã çšã ãã®ã¢ãããŒãã䜿çšãããšããã¹ãã®éçºæéãå€§å¹ ã«ççž®ã§ããŸãã
ãã®äžé£ã®èšäºã¯ã 以åã®ããŒãã€ã«ããšå€ãã®ç¹ã§äŒŒãŠãããããç©èªã®æ§é ã¯äŒŒãŠããŸãã ãã®ãã¹ãŠããªãå¿ èŠãªã®ãã説æããŸãã次ã«ãããããã£ãšãžã§ãã¬ãŒã¿ãŒã®ããªãºã ãéããŠäžçãèŠãããšãåŠã³ãããã«è€éãªãã®ã«é²ã¿ãŸãã ã«èå³ããããŸããïŒ ç«ããé¡ãããŸãã
ãµã€ã¯ã«æ§é
- ã¯ããã«
- çºé»æ©
- ããããã£
- æå°åãšç¶æ ãã¹ã
- çµ±åãšèšå®
ã¯ããã«
åäœãã¹ãã¯ããœãããŠã§ã¢éçºã§æãéèŠãªã¢ãããŒãã®1ã€ã§ãã ããã°ã©ã ãã³ã³ãã€ã«äžã«åã·ã¹ãã ã®ã¬ãã«ã§ãã§ãã¯ã«åæ ŒããŠããè«çãšã©ãŒãå«ãŸããŠããªããšããæå³ã§ã¯ãããŸããã ã€ãŸããããã°ã©ãã³ã°èšèªãã©ãã»ã©åŒ·åã§ãã£ãŠããã³ãŒãã®ãã¹ãã¯äžå¯æ¬ ã§ãã ãã ãããã¹ãã®ã³ã¹ãã¯éåžžã«é«ããªããŸããè²»ããããå·¥æ°ã«å ããŠãåäœãã¹ãã®æ¥åžžçãªèšè¿°ã«é人éçãªåªåãããå¿ èŠããããŸãã ãã®ãããå€ãã®é¡§å®¢ã¯ãã¹ããç¯çŽããŸããå€ãã®ããã°ã©ããŒã¯ãããéåžžã«åãã§äœ¿çšããŠããŸãã
åæããèšå€§ãªæ°ã®ã±ãŒã¹ãã«ããŒããåãã¿ã€ãã®æ§ææ§é ãæ¯æ¥æžãããšã¯çãããåã³ã§ãã æ®å¿µãªãããé¢æ°åèšèªã®ã¿ã€ãã»ãŒãã³ãŒãã§ãããã¹ãããå¿ èŠããããŸãã ãŸããæ©èœãã©ãã€ã ãé©çšããããšã§åäœãã¹ããå€§å¹ ã«å®¹æã«ãªããŸããïŒå¯äœçšããªããããå°æ°ã®ãšããžã±ãŒã¹ãèæ ®ããŠç¶æ ãã¹ããå®å šã«å¿ããããšãã§ããŸãïŒããã¹ãã³ãŒãã®éã¯å€§å¹ ã«åæžãããŸããã ããã«ãæåãã¹ãã¯ã³ãŒãã«ããçšåºŠã®èªä¿¡ãäžããŸãããæéã®çµéãšãšãã«èŠèœãšããç¹å®ã®ã±ãŒã¹ãèŠã€ãããªãããšãä¿èšŒããããšã¯ã§ããŸããã
ScalaCheckã®ã¢ãããŒãã«ããã次ã®æœè±¡åã¬ãã«ã«ç§»è¡ãããã®ã«ãŒãã³ã®éèŠãªéšåãåé¿ããªããããã¹ãã³ãŒãã®å¯èªæ§ãé«ãããµã€ãºãå°ããããããšãã§ããŸãïŒä¿å®æ§ã«ãã©ã¹ã®åœ±é¿ãäžããŸãïŒã ãã¹ãã«ããã³ãŒãã®ã«ãã¬ããžãèããå¢å ããŸãã ãããŠããããéæããããã«ãããã€ãã®æ°ããæŠå¿µã«ç²Ÿéããå¿ èŠããããŸãã
ããããã£æåãã¹ã
ããããã£ãšã¯
ãŸããããããã£ãšã¯äœããèŠãŠã¿ãŸãããã ç°¡åã«èšãã°ãããããã£ã¯ããã¹ããããé¢æ°ã®å ¥åå€ãšãããã§åŸãããçµæãé¢é£ä»ããè«çã¹ããŒãã¡ã³ãã§ãã ããã«ãããã§ãããããããã£ããšããèšèã¯ãæ¥åžžã®ããã°ã©ããŒã®æå³ïŒç¹å®ã®ãªããžã§ã¯ãã«å±ããããŒã¿ïŒã§ã¯ãªããç¹å®ã®ãªããžã§ã¯ãã»ããã«å¯ŸããŠå®å šã«æå¹ãªç¹å®ã®æ³åãšããŠã®æ°åŠçãªæå³ã§ç解ããå¿ èŠããããŸãã ããšãã°ãå®æ°ã®ä»£æ°ã«ãããçµåæ§ãŸãã¯åé æ§ã®ç¹æ§ãæãåºããŠãã ããã
ããããã£ããã¹ããããšãããã¹ããããé¢æ°ã®å®è£
ã®è©³çŽ°ã¯æ°ã«ããŸãããã
ãã ãããã®å
¥åããã³åºåããŒã¿ãä»æ§ã®ã¿ã ããšãã°ãã©ã€ããããèšèªã§æžããã次ã®åçŽãªããããã£ãäŸã«ãšã£ãŠã¿ãŸãããã
âx â â: x â 0 â¹ x² > 0
Leibnizkyãç解ããŠããªãå Žåã¯ã絶æããªãã§ãã ããããã¹ãŠãScalaã«çœ®ãããŸãã
ScalaCheckã䜿çšãããšãã»ãšãã©å ã®æ°åŠç圢åŒã§èšè¿°ã§ããŸãã
forall { x: Double => (x != 0) ==> x * x > 0 }
ãã·ã¢èªã§ã¯ãããŒãã«çãããªãå®æ°xã®å Žåãx²ã¯åžžã«ãŒããã倧ãããªããŸããã
èè ã¯ãDouble
åãå°ãtheã§ãªãããšãããç¥ã£ãŠããŸããã
èšèé£ãã®çµ¶å¯Ÿçãªæ£ç¢ºãã®è¡šçŸã®ç°¡çŽ åã¯ç ç²ã«ããªããã°ãªããªãã§ãããã
ã芧ã®ãšããããã®ããããã£ã¯ãJUnitã®åŸæ¥ã®ã¢ãµãŒã·ã§ã³ãã¹ããããé«ãã¬ãã«ã®æœè±¡åãè¡šããŸãã ãã ããæçµçã«ã¯ãã¹ãŠããããã«åž°çããŸããScalaCheckã¯ãããããã£ã®æœè±¡çãªèšè¿°ã«åºã¥ããŠãæã§æžããã®ãšåçã®å質ã®åå¥å€ã®éåžžã«å ·äœçãªãã¹ããçæããŸãã
ããããã£ã¯çè«ã§ã¯ãããŸãã
JUnit4ã«ã¯ã çè«ãšåŒã°ããèå³æ·±ãã¡ã«ããºã ããããŸãã ïŒããããããã¯ä»®èª¬ãšãåŒã°ããŸã...ïŒçè«ã¯ScalaCheckãšéåžžã«ãã䌌ãæ¹æ³ã§æ©èœããŸãããã©ã³ãã ãªå ¥åããŒã¿ãçæããŠæå°åïŒ çž®å° ïŒãå®è¡ããæ¹æ³ãããããŸããã
æ²ããããªãç§ã¯ç解ã§ããçšèªãçž®å°ãã®ããè¯ã翻蚳ãçºæããŸããã§ãã
ãæå°åãããããã·ã¢èªã«ã ããŸãæ£ããèãããŸããããããè¯ãã§ãã
ç§ã®ä»ã®è©Šã¿ããã
ããã§ã¯ãJUnitãã¥ãŒã®çè«ãšã¯æ£ç¢ºã«ã¯äœã§ããïŒ ãŸã第äžã«ãããã¯ç¹å¥ãªã¿ã€ãã®åäœãã¹ãã§ãã çè«ã¯ããã¹ãããŒã¿ã®ç¹å®ã®ã»ããïŒãããã¯ããŒã¿ãã€ã³ããšåŒã°ããŸã ïŒããã®åèŠçŽ ã«å¯ŸããŠäœããã®æ¡ä»¶ãçã§ãããã©ããããã§ãã¯ããŸãã ããã«ãããæ€èšŒããžãã¯ãäžåºŠããã°ã©ã ããŠãããããŸããŸãªããŒã¿ã»ããã§ãã°ããå®è¡ã§ããŸãã
ã¡ãœãããçè«ã«ããã«ã¯ãããã«å¿ããŠæ³šéãä»ããå¿
èŠããããŸãã @Theory
è¿œå ã@Theory
ã å
¥åããŒã¿ã«ã¯@DataPoint
ãšããŠæ³šéãä»ããã@DataPoint
ã ããã¯ãã©ã³ããŒããã¹ããè€æ°åïŒåããŒã¿ãã€ã³ãã«1åïŒå®è¡ããããšãæšæž¬ããã®ã«ååã§ãã 以äžã¯ãJUnitã®ããã¥ã¡ã³ããããã£ããåçšãããå°ããªäŸã§ãã
@RunWith(Theories.class) public class UserTest { // â . @DataPoint public static String GOOD_USERNAME = "optimus"; // â , . @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime"; @Theory public void filenameIncludesUsername(String username) { assumeThat(username, not(containsString("/"))); assertThat(new User(username).configFileName(), containsString(username)); } }
ãã®ã¡ã«ããºã ã¯ãScalaCheckã§äœ¿çšãããã¡ã«ããºã ã«äŒŒãŠããŸãã 2ã€ã®å°ããªéãã®ã¿ããããŸãã
- ScalaCheckèªäœããã¹ãããŒã¿ãçæããŸãã
- ãã¹ããäžéšã®ããŒã¿ã»ããã§ã¯ã©ãã·ã¥ããå ŽåãScalaCheckã¯åäŸã§ç°¡åã«çµäºããããšããŸããããã«åçŽãªç¹æ®ãªã±ãŒã¹ãéžæããŠãããã«ãããã°ãä¿é²ããŸãã
ãããã®éãã«ãããScalaCheckã¯ãã³ãŒããµã€ãºãšãã¹ãæ°ã®äž¡æ¹ã®é¢ã§çè«ãæã¡ç Žãããšãã§ããŸãã ãããããŸã çè«ã«ã€ããŠãã£ãšç¥ãããå Žåã¯ã次ã®ããšãã§ããŸãã
ããã§ãããã«ã€ããŠèªãã§ãã ãã ã
ããããã£ããŒã¹ã®ã¢ãããŒãã®é·æãšçæ
èªè ã®çãã«åããŠãScalaCheckã¯ScalaTestãæªåé«ãJUnitã«å®å šã«åã£ãŠä»£ãããã®ã§ã¯ãªããåäœãã¹ãããã»ã¹ã«æ¬¡ã®ãããªè¿œå ã®å©ç¹ãããããããã«äœæãããŸããã
- ç°¡æœãïŒã³ãŒããå°ãªã-æšæºïŒã¢ãµãŒã·ã§ã³ããŒã¹ïŒã¢ãããŒããšæ¯èŒããŠã«ãã¬ããžãé«ã
- é«ã¬ãã«ïŒç¹å®ã®ã±ãŒã¹ã§ã¯ãªããå ¥åå šè¬ã«çŠç¹ãåœãŠãŠããŸãã
- æå°åïŒäœããå£ããŠããå Žåããããã¯æ£ç¢ºã«ã©ããèŠã€ããã®ã«åœ¹ç«ã¡ãŸãïŒãŸãã¯ç§ãã¡ã¯èªåèªèº«ãå©ããŸãïŒã
- ã³ã³ããŒãã³ãããšã«ãã¹ããããããããŠããããšããŠãã¹ãããæ¹ãç°¡åãªãšã³ãã£ãã£ã®ååšã
ãã ããããããã£æåã®ãã¹ãã¯ç¹å¹è¬ã§ã¯ãããŸããã
ãã®ã¢ãããŒãã«ã¯æ¬ ç¹ããããŸãã
- æå¶ãããæ©èœã®ãã¹ãæéã¯ãããªããæ§ãã®æã«moonããããã«ããŸãã ïŒå¯èœã§ãããããã¯ãã©ã¹ã§ããç§ã®å®è·µã§ã¯ãScalaCheckã®å®è£ ã«ããããã¹ãŠã®ãããžã§ã¯ãåå è ãæé©åã«ã€ããŠèããããã«ãªã£ãå Žåãç¥ã£ãŠããŸããïŒ
- 誀ã£ãå®å¿æã ScalaCheckã䜿çšãããšããã¹ãã§ãã¹ãŠãã«ããŒã§ãããšç°¡åã«ä¿¡ããããŸããããŸã£ããããã§ã¯ãªãããšããããããŸãã
- å¢çæ¡ä»¶ã®åœ±é¿ãåããªãã
- ãã¹ãã»ããã®åäžãªã©ã³ãã ååžã äžè¬ã«ãããã¯è¯ãããšã§ãããå¿ ããã䟿å©ã§ã¯ãããŸããã
ãã€äœ¿çšããŸããïŒ
ScalaCheckã¯ãä»ã®ãã¹ããã¬ãŒã ã¯ãŒã¯ãšåæ§ã«äœ¿çšã§ããŸãã å°ãéã£ãèãæ¹ãããå¿ èŠããããŸãããçµå±ãScalaCheckã¯ã»ãšãã©ãã¹ãŠã®ãã¹ããæžãããšãã§ããŸã-åžžã«æãå¹æçã§äŸ¿å©ã§èªã¿ãããæ¹æ³ã§ã¯ãããŸããã ãã ããScalaCheckãæ¬åœã«åªããŠããé åããããŸãã
- å ¥åããŒã¿ã«éåžžã«ææãªã³ãŒãã
- ç¶æ ãã·ã³ãŸãã¯ç¶æ äŸåã·ã¹ãã ã
- ããŒãµãŒïŒç§ã¯å人çã«ScalaCheckã䜿çšããŠããŸãïŒ;
- ããŸããŸãªããŒã¿ã³ã³ããŒã¿ãŒ ïŒ
- ããªããŒã¿ãŒ
- åé¡å;
- ã¢ã°ãªã²ãŒã¿ãŒ
- éžå¥æ©ãªã©
- Spark RDDãããã³Hadoopã®ããããŒãšã¬ãã¥ãŒãµãŒã
ã¹ã«ã©ãã§ãã¯
ã©ã€ãã©ãªæ©èœ
ScalaCheckã¯æ¬¡ã®ãšããã§ãã
- ã³ã³ãã¯ãã©ã€ãã©ãªïŒã³ãŒãä»ã20ãã¡ã€ã«æªæºïŒ;
- è¿œå ã®äŸåé¢ä¿ã®æ¬ åŠ;
- å éšç¶æ ã®ãã¹ãã®ãµããŒãïŒã¹ããŒããã«ãã¹ãïŒ;
- æ¬äŒŒä¹±æ°ãžã§ãã¬ãŒã¿ãšããŠ
java.util.Random
ã䜿çšããããšãæåŠããŸãïŒããã«ãScalaCheckã¯ãreturnã䜿çšããæ€çŽ¢ã䜿çšããŠãã©ã³ãã ãªãã¹ãã»ãããç¹°ãè¿ãããªãããšãæ éã«ç¢ºèªããŸãïŒã - scala-jsããã³dottyã®ãµããŒãã
java.util.Random
å ã§ã¯ã ç·åœ¢ååæ³ã䜿çšãããŸã
æ¬äŒŒã©ã³ãã ã·ãŒã±ã³ã¹ã®çæïŒä»¥é-LCGïŒã ãã£ãšã§ãã
å ¬åŒææžããèªã¿ãã ããã LCGã¯ååã«æäŸããŸãã
æ¬äŒŒä¹±æ°çæã®å質ãã»ãšãã©ã®å Žåã«äœ¿çšãããŸã
ã©ã€ãã©ãªã¯ãã·ã³ãã«ããšé«ãããã©ãŒãã³ã¹ã®ã¿ã«äŸåããŠããŸãã
ScalaCheckã¯ç¬èªã®ãžã§ãã¬ãŒã¿ãŒã䜿çšããŸãã
æ·±å»ãªçµ±èšã¢ããªã±ãŒã·ã§ã³ã ãžã§ãã¬ãŒã¿ãŒã®è©³çŽ°ã確èªã§ããŸã
ãã¡ã ã
æºåäœæ¥
ããããã£æåã®ãã¹ããç¹ã«ScalaCheckãå¿ èŠãã©ããã決å®ããããæºåäœæ¥ãå§ããŸãããã ãããžã§ã¯ãã«æ¬¡ã®äŸåé¢ä¿ãè¿œå ããŸãïŒèªè ã®çãããæ¢ã«Scala 2.12ã«åãæ¿ããŠããããšãé¡ã£ãŠããŸãïŒã
<!-- sbt gradle, , Maven. --> <dependency> <groupId>org.scalacheck</groupId> <artifactId>scalacheck_2.12</artifactId> <version>1.13.4</version> </dependency>
ãŸããææ°ããŒãžã§ã³ã䜿çšããŠããããšãåæãšããŠããŸãã Scala 2.12ãšçµã¿åãããŠã©ã€ãã©ãªã®å€ãããŒãžã§ã³ã䜿çšãããšåé¡ãçºçããŸãã 泚æããŠãã ããã
åè¿°ã®ããã«ãScalaCheckã¯ãããããã£ãšãžã§ãã¬ãŒã¿ãŒãšãã2ã€ã®äž»èŠãªæŠå¿µã«åºã¥ããŠæ§ç¯ãããŠããŸãã ããããã£ã¯ããã·ã¢ã®ããã°ãå«ãå€ãã®ããã°ã§ããåãäžããããŠããŸãã ãããã£ãŠããžã§ãã¬ãŒã¿ãŒã«ãã£ãšæ³šæãåããããšããŸãã ãã®ããŒãã§ã¯ãããããã£ãšãžã§ãã¬ãŒã¿ã®äž¡æ¹ã«ã€ããŠç°¡åã«èª¬æããŸãã
ããããã£ã«ã€ããŠå°ã
ããããã£ã¯ããã¹ããããæå°ã¢ãžã¥ãŒã«ã§ãã org.scalacheck.Prop
ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã«ãã£ãŠæ瀺ãããŸãã æãç°¡åãªäŸïŒ
import org.scalacheck.Prop val propStringLengthAfterConcat = Prop forAll { s: String => val len = s.length (s + s).length == len + len } // , // val propDivByZero = Prop.throws(classOf[ArithmeticException] {1/0}) // , // , // IndexOutOfBoundsException val propListIndexOutOfBounds = Prop forAll { xs: List[Int] => Prop.throws(classOf[IndexOutOfBoundsException]) { xs(xs.length + 1) }
ãžã§ãã¬ãŒã¿ãŒã«ã€ããŠ
å®éã«ã¯ããžã§ãã¬ãŒã¿ã¯ããããã£ä»¥äžã«äœæããå¿
èŠããããŸãã ãããã䜿çšããã«ã¯ã org.scalacheck.Gen
ãã€ã³ããŒãããå¿
èŠããããŸãã
import org.scalacheck.Gen // , // . val binaryDigit = Gen.choose(0, 1) val octDigit = Gen.choose(0, 7) // , // . val vowel = Gen.oneOf('a', 'e', 'i', 'o', 'u')
ScalaCheckã«ã¯ãæšæºã¿ã€ãçšã®æ¢è£œã®ãžã§ãã¬ãŒã¿ãŒã®ã»ããããããŸãã
// , . val alphaLower = Gen.alphaLowerChar // , ( // , , // ). val identifier = Gen.identifier // , Long. val natural = Gen.posNum[Long]
map
ãé©çšããããšã§æ¢åã®ãžã§ãã¬ãŒã¿ãŒãçµã¿åãããŠç解ããããšãã§ããŸãã
val personGen = for { charValue <- Gen.oneOf("Jason", "Oliver", "Jessica", "Olivia") ageValue <- Gen.posNum[Int] } yield Person (name = nameValue, age = ageValue)
ããããã£ãšãžã§ãã¬ãŒã¿ã®äž¡æ¹ã«ã€ããŠã¯ã次ã®èšäºã§è©³ããæ€èšããŸãã ã·ãªãŒãºã®æ¬¡ã®èšäºã¯ãžã§ãã¬ãŒã¿ãŒã«ã€ããŠã§ãã èªãã§ãããŠããããšããé£çµ¡ãåãåãã