JUnitãš
TestNGãäŸãšããŠäœ¿çšãã以åã®èšäºã§ã¯ã
ãã¹ãé§åéçºïŒTDDïŒãš
ããŒã¿é§åãã¹ãïŒDDTïŒã«ã€ããŠèšåããŸããã ããããç©æ¥µçã«äººæ°ãåŸãŠããå¥ã®ã¢ãããŒãã
è¡åé§ååéçºïŒBDDïŒããããŸãã ããã¯TDDãã¯ãããžã®ãã®ãããªéçºã§ããããã¹ãã¯äžéšã®ã·ã¹ãã ã³ã³ããŒãã³ãã®ãã¹ãã§ã¯ãªããæ©èœèŠä»¶ãšããŠèŠãªãããŸãã TDDããã¹ããã¡ãœãããªã©ã®æŠå¿µã䜿çšããå ŽåãBDDã®å Žåã¯ä»æ§ãšèŠä»¶ã§ãã ãã®ææ³ã«ã€ããŠã¯ããã§ã«ä»¥åã«habrã§è©±ããŸããïŒ
ãã®ã¢ãããŒãã¯ãJUnitãšTestNGã®äž¡æ¹ã䜿çšããŠé©çšã§ããŸãã ãã ããBDDå°çšã«èª¿æŽãããä»ã®ããŒã«ããããŸãã ãã®èšäºã§ã¯ããã®ãããªãã¬ãŒã ã¯ãŒã¯ã«ã€ããŠèª¬æããŸãã ããã¯
Spock FrameworkãšåŒã°ããBDDã®åçã ãã§ãªã
Groovyã®å©ç¹ãå
ŒãåããŠããŸãã ã¯ããã¯ããGroovyã Groovyã䜿çšãããŸãããJavaã³ãŒãã®ãã¹ãã«ã䜿çšãããŸãã 䜿çšäŸã¯ãSpringãGrailsãTapestry5ã§ãã é¢çœãïŒ æ¬¡ã«èªã¿é²ããŠãã ããã
è¡åé§åéçº
ããã§ããããäœã§ããããæãåºãããŠãã ããã äŸãèããŠã¿ãŸãããã antãã¿ãŒã³ã§åäœãããŠãŒãã£ãªãã£ã¯ãããŸããïŒãããã¯ãã¡ã€ã«ãååŸããããã®ãã®ã§ãïŒã -ä»»æã®1æåã®ã¿ã*-ä»»æã®æ°ã®ä»»æã®æåã**-ä»»æã®ãã¹ã 次ã®ããã«ãªããŸãã
public abstract class PathUtils { public static boolean matchAntPath(final String path, final String pattern) {
ã©ã¡ãã®ã¡ãœããããæž¡ãããæååããã¿ãŒã³ã«äžèŽãããã©ããããã§ãã¯ããŸããã
matchAntPatternã¡ãœããã¯ãã¹ãèæ
®ããã«ããŒã«ã«ãã¿ãŒã³
ã®ã¿ãèæ
®ãã
matchAntPathã¯å®å
šãªãã¹ãåããŸãã TDDã®ååã«åŸã£ãŠãå
¥åããŒã¿ã®ã»ãããšæåŸ
ãããçµæã®ã»ããã䜿çšããŠãåã¡ãœããã®ãã¹ããäœæãããŸãã
public class TestPathUtils extends Assert { @Test(dataProvider = "matchAntPatternData") public void testMatchAntPattern(final String pattern, final String text, final boolean expected) { final boolean actual = PathUtils.matchAntPattern(text, pattern); assertEquals(actual, expected); } @Test(dataProvider = "matchAntPathData") public void testMatchAntPath(final String pattern, final String path, final boolean expected) { final boolean actual = PathUtils.matchAntPath(path, pattern); assertEquals(actual, expected); } }
ãããããäŸå€ãã¹ããŒããå¿
èŠãããå Žåã誀ã£ããã©ã¡ãŒã¿ãŒã®ãã¹ããããã«è¿œå ãããŸãã ããã§ã¯ãBDDã®èŠ³ç¹ããèŠãŠã¿ãŸãããã
ãã¹ãã¯åãªããã¹ãã§ã¯ãªããä»æ§ã§ãããã¡ãœããã§ã¯ãªãèŠä»¶ã§æ§æãããŠããŸãã
PathUtilsã®èŠä»¶ã
匷調衚瀺ããŸãã
- ã·ã³ãã«ïŒ ãã³ãã¬ãŒãå
ã®ãã§ãã¯å¯Ÿè±¡ã®æååå
ã®ä»»æã®æåãšåçã§ããå¿
èŠããããŸã
- ã·ã³ãã«ïŒ ãã³ãã¬ãŒãã§ã¯ããã§ãã¯å¯Ÿè±¡ã®æååã®1æåãš1æåã®ã¿ã«çžåœããå¿
èŠããããŸã
- ãã¿ãŒã³å
ã®*æåã¯ããã§ãã¯å¯Ÿè±¡ã®æååå
ã®ä»»æã®æåãšåçã§ãªããã°ãªããŸãã
- ãã¿ãŒã³ã®*æåã¯ããã§ãã¯ããæååã®ä»»æã®æ°ã®æåãšåçã§ããå¿
èŠããããŸã
- ãã§ãã¯ãããã³ãã¬ãŒããšæååã®å€ã¯nullã§ãã£ãŠã¯ãªããŸãã
ããã«ãåèŠä»¶ã«ã¯ç¬èªã®æ€èšŒã¹ã¯ãªããããããéåžžã¯ããã®ãšãã«æå®ãããçšèªã䜿çšãããŸãã äžãããã-ã¹ã¯ãªããã®éå§ã®èšå®ããã€-çç±ããããŠ-ã¹ã¯ãªããã®æ¡ä»¶ã äŸïŒ
Given: PathUtils --- When: matchAntPattern(null, "some string") --- Then: NullPointerException should be thrown
ãããã£ãŠããã¹ãã¯æ¬¡ã®ããã«ãªããŸãã
public class PathUtilsSpec extends Assert { @Test public void question_character_should_mean_any_character() { assertTrue(PathUtils.matchAntPattern("abb", "a?b")); assertTrue(PathUtils.matchAntPattern("a1b", "a?b")); assertTrue(PathUtils.matchAntPattern("a@b", "a?b")); assertTrue(PathUtils.matchAntPath("abb", "a?b")); assertTrue(PathUtils.matchAntPath("a1b", "a?b")); assertTrue(PathUtils.matchAntPath("a@b", "a?b"));
次ã«ãSpock Frameworkã«ã€ããŠè©³ãã説æããŸãã
äž»ãªæ©èœ
å
ã»ã©èšã£ãããã«ãã¹ã¯ãªããã¯Groovyã§æžãããŠããŸãã ããã¯è¯ãã§ããæªãã§ããïŒ
Groovyã¯åå¿è
ã§ã
15åã§èªãããšãã§ããŸã
-ç°¡åãªæŠèŠã§ãã
ä»æ§ã¯
spock.lang.Specificationããç¶æ¿ããå¿
èŠããããŸãã ãã£ãŒã«ãããã£ã¯ã¹ãã£ã¡ãœãããæ©èœã¹ã¯ãªããããã«ããŒã¡ãœãããå«ããããšãã§ããŸãã
ããã©ã«ãã§ã¯ããã£ãŒã«ãã¯ã¹ã¯ãªããéã§å
±æãããŸããã ããã·ããªãªããã®ãã£ãŒã«ãã®å€æŽã¯ãå¥ã®ã·ããªãªããã¯èŠããŸããã å
±æããã«ã¯ã
@Sharedã䜿çšããŠæ³šéãä»ããããšãã§ããŸãã
ã€ã³ã¹ããŒã«æ¹æ³ã¯æ¬¡ã®ãšããã§ãã
- setupïŒïŒ -åã¹ã¯ãªããã®åã«å®è¡ããããJUnitã®@Beforeã®é¡äŒŒç©
- cleanupïŒïŒ -JUnitã®@Afterã«çžåœããåã¹ã¯ãªããã®åŸã«å®è¡ãããŸã
- setupSpecïŒïŒ -JUnitã®@BeforeClassã®é¡äŒŒç©ãä»æ§ã®æåã®ã¹ã¯ãªããã®åã«å®è¡ãããŸã
- cleanupSpecïŒïŒ -ä»æ§ã®æåŸã®ã¹ã¯ãªããã®åŸã«å®è¡ããããJUnitã®@AfterClassã«é¡äŒŒ
ä»ã®ãã¹ããã¬ãŒã ã¯ãŒã¯ãšåæ§ã«ããããã®ã¡ãœããã¯ãåã¹ã¯ãªããã«åãã€ã³ã¹ããŒã«ã³ãŒããèšè¿°ããªãããã«ããããã«äœ¿çšãããŸãã
èŠä»¶ã·ããªãªã¯ãä»æ§ã®äž»èŠéšåã§ãã ããã§ã³ã³ããŒãã³ãã®åäœã説æãããŸãã æååãªãã©ã«ã䜿çšããŠåŒã³åºãã®ãæ
£ç¿ã§ãããä»»æã®æåã䜿çšã§ããŸããäž»ãªããšã¯ããã®ååããã®ã¹ã¯ãªããã®æ©èœãã§ããã ãæ確ã«èª¬æããããšã§ãã ããšãã°ããã®å ŽåïŒ
class PathUtilsSpec extends Specification { def "? character should mean any character"() {
åã·ããªãªã¯ãããã¯ã§æ§æãããŠãããã©ãã«ã§ç€ºãããŠããŸãã
- setupã¯setupïŒïŒã€ã³ã¹ããŒã«æ¹æ³ãšåãã§ãç¹å®ã®ã·ããªãªã«ã®ã¿é©çšãããŸãã æ®ãã®ãããã¯ã®åã«é
眮ããå¿
èŠããããç¹°ãè¿ããªãã§ãã ããã ã»ããã¢ããã©ãã«ãæ¬ èœããŠããå¯èœæ§ããããŸããsetupã®ä»£ããã«æå®ããããšãã§ããŸã ãããã¯ãèªã¿ãããããããã«è¡ãããŸãïŒç¹å®ã®å ŽåïŒ
- cleanupã¯cleanupïŒïŒã¡ãœãããšåãã§ãç¹å®ã®ã¹ã¯ãªããã«ã®ã¿é©çšãããŸãã whereãããã¯ïŒååšããå ŽåïŒã®åã®ã¹ã¯ãªããã®æåŸã«ããå¿
èŠããããç¹°ãè¿ããªãã§ãã ãã
- when-thenã¯å®è¡ã®çç±ãšæ¡ä»¶ã§ãã whenéšåã§ã¯ãå€æ°ãé垞宣èšãããå¿
èŠãªã¢ã¯ã·ã§ã³ãå®è¡ããããã®éšåã§ããã€ãã®æ¡ä»¶ããã§ãã¯ãããŸãã ããã«ã¯ãæ¡ä»¶ã®ãã§ãã¯ãäŸå€ã®ã¹ããŒã®ãã§ãã¯ããŸãã¯ã¢ãã¯ãªããžã§ã¯ãã§å®è¡ãããã¡ãœããã®åŸ
æ©ããããŸãã ãã®ãããã¯ã¯ç¹°ãè¿ãããšãã§ããŸããããã¬ãŒã ã¯ãŒã¯ã®äœæè
ã¯é¢äžããªãããšãæšå¥šããŠããŸããé©åãªã¹ã¯ãªããã«ã¯ã1ã5åã®ãã®ãããªãããã¯ãå«ããå¿
èŠããããŸã
- expectã¯ãã¢ã¯ã·ã§ã³ãšæ€èšŒãåãåŒã«å«ãŸããç°¡ç¥åãããwhen-thenãããã¯ã§ã
- ãã¹ãçšã®ããŒã¿ã»ãããäœæããããã«èšèšãããTestNGã®@DataProviderã®é¡äŒŒç©
ããŠããã¹ãŠã®è©³çŽ°ã«ã€ããŠã å¥ã®äŸãèããŠã¿ãŸãããã ãã¡ã€ã«ãæ€çŽ¢ããããã«èšèšããã
PathSearcher㯠ããã¡ã€ã«ã®ãã£ã«ã¿ãŒãšããŠantãã¿ãŒã³ã䜿çšããŸãã
public class PathSearcher { public PathSearcher(final String path) {...} public PathSearcher include(final String... patterns) {...} public PathSearcher exclude(final String... patterns) {...} public Set<String> search() {...} }
ããã¡ã€ã«ã·ã¹ãã äžã®ãã¡ã€ã«ãæ€çŽ¢ããå¿
èŠããããŸãããšããèŠä»¶ãèšè¿°ããŸãã
class PathSearcherSpec extends Specification { def "it should search files under the file system"() { given: def searcher = PathSearcher.create(inClasspath("test1")) when: def results = searcher.search(); then: results.containsAll(["1.txt", "2.txt"]); results.size() == 2 } private String inClasspath(path) { return ClassLoader.getSystemResource(path).toExternalForm() } }
ãã®ããã
ã¯ã©ã¹ãã¹ãã
test1ãã©ã«ããŒãæ€çŽ¢ããæ€çŽ¢ãšã³ãžã³ãæ€çŽ¢ãå®è¡æ¡ä»¶ã確èªãã-æ€çŽ¢ãšã³ãžã³ã¯ãã¡ã€ã«ãèŠã€ããå¿
èŠããããŸãã
inClasspathã¯ã
classpathãããã¡ã€ã«ã®çµ¶å¯Ÿãã¹ãè¿ããã«ããŒã¡ãœããã§ãã
PathUtilsã®å¥ã®äŸããã§ãã¯ãããã³ãã¬ãŒããšæååã®å€ã¯nullã«ã§ããŸããã
class PathUtilsSpec extends Specification { def "null parameter values are not allowed"() { when: PathUtils.matchAntPattern(null, "some string") then: thrown(NullPointerException) when: PathUtils.matchAntPattern("some string", null) then: thrown(NullPointerException) when: PathUtils.matchAntPath(null, "some string") then: thrown(NullPointerException) when: PathUtils.matchAntPath("some string", null) then: thrown(NullPointerException) } }
ããã«ã
ã¹ããŒãããïŒ...ïŒã¡ãœããããããŸããããã¯ãæå®ãããäŸå€ã®äºæ³ã§ã
ãnotThrownïŒ...ïŒã¡ãœãããš
noExceptionThrownïŒïŒããããŸãã ãããã¯ãç¹å®ã®äŸå€ãã¹ããŒãããããšã確èªããããã®ãã®ã§ãã ãŸãããã®éšåã§ã¯ãã¢ãã¯ãªããžã§ã¯ãã®ããã€ãã®ã¡ãœãããžã®æåŸ
ããããããããŸãããããããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãã å¥ã®äŸïŒ
class PathUtilsSpec extends Specification { def "? character should mean any character"() { expect: PathUtils.matchAntPattern("abb", "a?b") PathUtils.matchAntPattern("a1b", "a?b") PathUtils.matchAntPattern("a@b", "a?b") PathUtils.matchAntPath("abb", "a?b") PathUtils.matchAntPath("a1b", "a?b") PathUtils.matchAntPath("a@b", "a?b") } }
ãã®äŸãããããããã«ã
ã〠ããããŠ
ãã®åŸã®äž¡æ¹ã®éšåã1ã€ã®æ¡ä»¶ã«çµåã§ããå Žåã
expectãããã¯ã䜿çšããæ¹ã䟿å©ã§ãã ãã®ã·ããªãªã¯ã
whereãããã¯ã䜿çšããŠãã©ã¡ãŒã¿ãŒåå¯èœã«ããããšã§æ¹åã§ããŸãã
class PathUtilsSpec extends Specification { def "? character should mean any character"() { expect: PathUtils.matchAntPattern(text, pattern) PathUtils.matchAntPath(text, pattern) where: pattern | text "ab?" | "abc" "ab?" | "ab1" "ab?" | "ab@" "a?b" | "abb" "a?b" | "a1b" "a?b" | "a@b" "?ab" | "aab" "?ab" | "1ab" "?ab" | "@ab" } }
ãŸãã¯ïŒ
class PathUtilsSpec extends Specification { def "? character should mean any character"() { expect: PathUtils.matchAntPattern(text, pattern) PathUtils.matchAntPath(text, pattern) where: pattern << ["ab?", "ab?", "ab?", "a?b", "a?b", "a?b", "?ab", "?ab", "?ab"] text << ["abc", "ab1", "ab@", "abb", "a1b", "a@b", "aab", "1ab", "@ab"] } }
ãŸãã¯ïŒ
class PathUtilsSpec extends Specification { def "? character should mean any character"() { expect: PathUtils.matchAntPattern(text, pattern) PathUtils.matchAntPath(text, pattern) where: [pattern, text] << [ ["ab?", "abc"], ["ab?", "ab1"], ["ab?", "ab@"], ["a?b", "abb"], ["a?b", "a1b"], ["a?b", "a@b"], ["?ab", "aab"], ["?ab", "1ab"], ["?ab", "@ab"] ] } }
ãŸãã¯ãã®ããã«ïŒ
class PathUtilsSpec extends Specification { def "? character should mean any character"() { expect: PathUtils.matchAntPattern(text, pattern) PathUtils.matchAntPath(text, pattern) where: [pattern, text] = sql.execute("select pattern, text from path_utils_test") } }
äŸãããã¹ãŠãæããã§ãããšæãã®ã§ãç§ã¯ããã«çŠç¹ãåãããŸããã
whereãããã¯ã§ã¯ã
@SharedãšããŠããŒã¯ãããŠããªããã£ãŒã«ãã¯äœ¿çšã§ããªãããšã«æ³šæããŠ
ãã ãã ã
çžäºäœçš
ãšãããããã¬ãŒã ã¯ãŒã¯ã䜿çšãããšãè¿œå ã®äŸåé¢ä¿ãªãã«ã¢ãã¯ãªããžã§ã¯ããæäœã§ããŸãã ã€ã³ã¿ãŒãã§ã€ã¹ããã³éæçµã¯ã©ã¹ã®mokaãäœæã§ããŸãã äœæã¯æ¬¡ã®ããã«ãªããŸãã
def dao1 = Mock(UserDAO) UserDAO dao2 = Mock()
ãã®ãããªãªããžã§ã¯ãèªäœã®æ»ãå€ãŸãã¯ã¡ãœããããªãŒããŒã©ã€ãã§ããŸãã èè
ã¯ãã®çžäºäœçšãåŒã³åºããŸãã
dao1.findAll() >> [ new User(name: "test1", description: "Test User"), new User(name: "test2", description: "Test User"), new User(name: "test3", description: "Test User") ] dao2.findAll() >> { throw new UnsupportedOperationException() }
çžäºäœçšã¯ãããŒã«ã«ïŒ
thenãããã¯ã§å®çŸ©ïŒããã³ã°ããŒãã«ïŒä»ã®å Žæã§å®çŸ©ïŒã§ãã ããŒã«ã«ã¯
ãã®ãããã¯ã§ã®ã¿äœ¿çšã§ããã°ããŒãã«ã¯å®çŸ©ã®ãã€ã³ãããã©ãã§ã䜿çšã§ããŸãã ãŸããããŒã«ã«ã€ã³ã¿ã©ã¯ã·ã§ã³ã®å Žåããããã®ãã¯ãŒãæå®ã§ããŸããããã¯ãã¡ãœããåŒã³åºãã®äºæ³æ°ã§ãã
class UserCacheSpec extends Specification { def users = [ new User(name: "test1", description: "Test User"), new User(name: "test2", description: "Test User"), new User(name: "test3", description: "Test User") ] def "dao should be used only once for all user searches until invalidated"() { setup: def dao = Mock(UserDAO) def cache = new UserCacheImpl(dao) when: cache.getUser("test1") cache.getUser("test2") cache.getUser("test3") cache.getUser("test4") then: 1 * dao.findAll() >> users } }
ãã®äŸã§ã¯ã
UserDAOçšã®ã¢ãã¯ãšããã®ã¢ãã¯ïŒã»ããã¢ãããããã¯ïŒã䜿çšããŠå®éã®
UserCacheãªããžã§ã¯ããäœæããŸãã 次ã«ãååïŒ
when- blockïŒã§è€æ°ã®ãŠãŒã¶ãŒãæ€çŽ¢ããæåŸã«ãæºåãããçµæãè¿ã
findAllã¡ãœããã1åã ãåŒã³åºãããããšã確èªããŸãã
çžäºäœçšã説æããã«ã¯ããã³ãã¬ãŒãã䜿çšã§ããŸãã
1 * dao.findAll() >> users (1..4) * dao.findAll() >> users (2.._) * dao.findAll() >> users (_..4) * dao.findAll() >> users _.findAll() >> users dao./find.*/(_) >> users
詳现ã¯
ãã¡ã ã
è¿œå æ©èœ
ã芧ã®ãšããããã¬ãŒã ã¯ãŒã¯ã«ã¯ãã§ã«å€ãã®æ©èœããããŸãã ããããä»ã®ãã¬ãŒã ã¯ãŒã¯ãšåæ§ã«ãæ©èœãæ¡åŒµããå¯èœæ§ããããŸãã äŸã¯çµã¿èŸŒã¿ã®æ¡åŒµæ©èœã§ãã
- @Timeout -JUnitã®@Testã® ã¿ã€ã ã¢ãŠãå±æ§ã«çžåœãããã¹ã¯ãªããã®æ倧ã¿ã€ã ã¢ãŠããèšå®ããŸã
- @Ignore -JUnitã®@Ignoreã«çžåœããã¹ã¯ãªãããç¡å¹ã«ããŸã
- @IgnoreRest-泚éä»ã以å€ã®ãã¹ãŠã®ã¹ã¯ãªãããç¡å¹ã«ããŸãã1ã€ã®ãã¹ãã®ã¿ããã§ãã¯ããå¿
èŠãããå Žåã«åœ¹ç«ã¡ãŸã
- @FailsWith-äºæ³ãããäŸå€ãèšå®ããŸããããã¯ãJUnitã®@Test㧠äºæ³ãããå±æ§ã®é¡äŒŒç©ã§ãã
- @Unroll-ãã©ã¡ãŒã¿ãŒåãããã¹ã¯ãªããã¯ãå埩ããšã«åå¥ã®ã¹ã¯ãªãããšããŠæå®ããå¿
èŠãããããšã瀺ããŸããããã§ã¯ãèŠä»¶åã®ãã³ãã¬ãŒããæå®ã§ããŸããããã©ã«ãã§ã¯ã ãïŒfeatureName [#iterationCount]ãã§ãã
class InternalExtensionsSpec extends Specification { @FailsWith(NumberFormatException) @Unroll("#featureName (#data)") def "integer parse method should throw exception for wrong parameters"() { Integer.parseInt(data) where: data << ["Hello, World!!!", "0x245", "1798237199878129387197238"] } @Ignore @Timeout(3) def "temporary disabled feature"() { setup: sleep(20000) } }
ä»ã®ãã¬ãŒã ã¯ãŒã¯ãšã®çµ±åã¯ãåå¥ã®ã¢ãžã¥ãŒã«ã§è¡ãããŸãã
- Spring-@ContextConfigurationïŒlocations = "application_context_xml"ïŒã䜿çšããŠä»æ§ã«æ³šéãä»ãããã @ Autowiredã䜿çšããŠãã£ãŒã«ãã«äŸåé¢ä¿ã泚å
¥ã§ããŸãã
@ContextConfiguration(locations = "context.xml") class SpringIntegrationSpec extends Specification { @Autowired String testSymbol def "test-symbol should be spring"() { expect: testSymbol == "spring" } }
- Guice-@UseModulesïŒguice_module_classïŒã䜿çšããŠä»æ§ã«æ³šéãä»ãããã @ Injectã䜿çšããŠãã£ãŒã«ãã«äŸåé¢ä¿ã泚å
¥ã§ããŸãã
public class GuiceModule extends AbstractModule { @Override protected void configure() { bind(String.class).annotatedWith(Names.named("test-symbol")).toInstance("guice"); } } @UseModules(GuiceModule) class GuiceIntegrationSpec extends Specification { @Inject @Named("test-symbol") String testSymbol def "test-symbol should be guice"() { expect: testSymbol == "guice" } }
- ã¿ãã¹ããªãŒ-ä»æ§ã«ã¯@SubModuleïŒtapestry_module_classïŒã䜿çšããŠæ³šéãä»ãããã @ Inject泚éã䜿çšããŠäŸåé¢ä¿ããã£ãŒã«ãã«æ¿å
¥ã§ããŸãã
public class TapestryModule { public void contributeApplicationDefaults(final MappedConfiguration<String, String> configuration) { configuration.add("test-symbol", "tapestry"); } } @SubModule(TapestryModule) class TapestryIntegrationSpec extends Specification { @Inject @Symbol("test-symbol") String testSymbol def "test-symbol should be tapestry"() { expect: testSymbol == "tapestry" } }
æãéèŠãªããšã¯ãç¬èªã®æ©èœãå¿
èŠãªå Žåã¯ãç¬èªã®æ¡åŒµæ©èœãè¿œå ã§ããããšã§ãã æ©èœãæ¡åŒµããããã®äž»èŠãªã¯ã©ã¹ïŒ
- IMethodInterceptorã¯ãIMethodInvocationãä»æ§ã¡ãœããããããã·ããããã®æåã®ãã®ã§ãããã¡ãœãããåŒã³åºãååŸã«ã³ãŒããè¿œå ã§ããŸããäœæ¥ãç°¡çŽ åããããã«ã AbstractMethodInterceptorã¯ã©ã¹ã䜿çšã§ããŸãã 2çªç®ã®ã¡ãœããã¯æåã®ã¡ãœãããã䜿ââçšã§ããå
ã®ïŒãããã·åãããïŒã¡ãœããã§åäœããŸã
- IGlobalExtension-ä»æ§ã¡ã¿ããŒã¿ïŒ SpecInfo ïŒãæäœã§ããŸããããã§ã¯ãä»æ§ã³ã³ããŒãã³ãïŒãã£ãŒã«ããã€ã³ã¹ããŒã«æ¹æ³ãèŠä»¶ã¹ã¯ãªããïŒã®ã¡ã¿ããŒã¿ã衚瀺ããç¬èªã®ã€ã³ã¿ãŒã»ãã¿ãŒãè¿œå ã§ããŸãã
- IAnnotationDrivenExtension-åã®ãã®ãšåãã§ãããã¿ã¹ã¯ãåçŽåããã ãã§ããæ¡åŒµæ©èœãç¹å®ã®æ³šéã«é¢é£ä»ããããŠããå Žåã AbstractAnnotationDrivenExtensionã¯ã©ã¹ã䜿çšããŠäœæ¥ãåçŽåã§ããŸãã
ç¬èªã®æ¡åŒµæ©èœãäœæããã«ã¯ã
IMethodInterceptorãä»æ§ã³ã³ããŒãã³ãã«è¿œå ãããå¯èœæ§ãé«ã
IGlobalExtensionãŸãã¯
IAnnotationDrivenExtensionäžäœã¯ã©ã¹ãäœæããå¿
èŠããããŸãã
æåŸã«ã
spiæ¡åŒµæ©èœã
META-INF / services / org.spockframework.runtime.extension.IGlobalExtensionã«è¿œå ããŸã ã
IAnnotationDrivenExtensionã®å Žå ã泚éã¯
@ExtensionAnnotationïŒextension_classïŒã䜿çšããŠæ³šéãä»ããå¿
èŠããããŸãã
æå®ãããåæ°ã ãã¹ã¯ãªãããå®è¡ããæ¡åŒµæ©èœã®äŸïŒ
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) @ExtensionAnnotation(RepeatExtension.class) public @interface Repeat { int value() default 1; } public class RepeatExtension extends AbstractAnnotationDrivenExtension<Repeat> { @Override public void visitFeatureAnnotation(Repeat annotation, FeatureInfo feature) { feature.addInterceptor(new RepeatInterceptor(annotation.value())); } } public class RepeatInterceptor extends AbstractMethodInterceptor{ private final int count; public RepeatInterceptor(int count) { this.count = count; } @Override public void interceptFeatureExecution(IMethodInvocation invocation) throws Throwable { for (int i = 0; i < count; i++) { invocation.proceed(); } } }
class CustomExtensionsSpec extends Specification { @Repeat(10) def "custom extension"() { expect: Integer.parseInt("123") == 123 } }
ãã¹ããå®è¡ãã
Spockãã¹ãã¯JUnit LauncherïŒ
Sputnik ïŒã䜿çšããŠå®è¡ããããããããŸããŸãªIDEã§æ£åžžã«åäœããŸãïŒèè
ãèšãããã«ãç§ã¯ã¢ã€ãã¢ã®äžã§ã®ã¿ç¢ºèªããŸããïŒã antãmavenãgradleããã®ãã¹ãã®èµ·åãæ§æããããšãã§ããŸãã èšå®ã«é¢ãããã¹ãŠã®å¿
èŠãªæ
å ±ã¯ã
ããã«ãããŸã ã
ãããèªåçšã«è¿œå ããŸããMavenã®äžã§å°ãèšå®ã確èªããŸããã èè
ã«ãã£ãŠææ¡ãããmaven3ã®äžã§åäœããŸããã§ããã ç§ã®èšå®ãªãã·ã§ã³ã¯æ¬¡ã®ãšããã§ãã
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.example</groupId> <artifactId>testing-example</artifactId> <version>1.0-SNAPSHOT</version> </parent> <groupId>com.example</groupId> <artifactId>testing-spock</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>Testing Spock Framework Example</name> <description> This is an example application that demonstrates Spock Framework usage. </description> <dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>${groovy-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> <version>${spock.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <testResources> <testResource> <directory>src/test/groovy</directory> </testResource> <testResource> <directory>src/test/resources</directory> </testResource> </testResources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <includes> <include>**/*Spec.groovy</include> </includes> </configuration> </plugin> <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>gmaven-plugin</artifactId> <version>${gmaven-version}</version> <configuration> <providerSelection>${gmaven-provider}</providerSelection> </configuration> <executions> <execution> <goals> <goal>testCompile</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>${groovy-version}</version> </dependency> </dependencies> </plugin> </plugins> </build> <properties> <groovy-version>1.7.10</groovy-version> <gmaven-version>1.3</gmaven-version> <gmaven-provider>1.7</gmaven-provider> <spock.version>0.5-groovy-1.7</spock.version> </properties> </project>
ãããã«
ãã®ãã°ããããã¬ãŒã ã¯ãŒã¯ã«æè¿åºäŒã£ããšããäºå®ã«ãããããããç§ã¯ãããå®éã«äœ¿çšããçµéšããããŸãããããã¯èœåã«ãããŠå£ãããããã€ãã®é¢ã§ä»ã®ãã¬ãŒã ã¯ãŒã¯ãåevenããŠãããšèªä¿¡ãæã£ãŠèšããŸãã ç§ã¯Groovyã§ãã¹ããæžãã®ãæ¬åœã«å¥œãã§ãBDDã«ã¬ã€ãããããã¹ããæžãã®ã奜ãã§ããã ãããã£ãŠãè©ŠããŠã¿ãããšããå§ãããŸãã
äŸã¯
ããã«ãããŸã ã
æåŠ