
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ
JUnit рдФрд░
TestNG рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ, рдореИрдВрдиреЗ
рдкрд░реАрдХреНрд╖рдг-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╡рд┐рдХрд╛рд╕ (TDD) рдФрд░
рдбреЗрдЯрд╛-рдЪрд╛рд▓рд┐рдд рдкрд░реАрдХреНрд╖рдг (DDT) рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ред рд▓реЗрдХрд┐рди рдПрдХ рдФрд░ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИ рдЬреЛ рд╕рдХреНрд░рд┐рдп рд░реВрдк рд╕реЗ рд▓реЛрдХрдкреНрд░рд┐рдпрддрд╛,
рд╡реНрдпрд╡рд╣рд╛рд░-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╡рд┐рдХрд╛рд╕ (рдмреАрдбреАрдбреА) рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣рд╛ рд╣реИред рдпрд╣ рдЯреАрдбреАрдбреА рддрдХрдиреАрдХ рдХрд╛ рдРрд╕рд╛ рд╡рд┐рдХрд╛рд╕ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдХреЛ рдХреБрдЫ рд╕рд┐рд╕реНрдЯрдо рдШрдЯрдХреЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рд░реВрдк рдореЗрдВ рджреЗрдЦрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдЯреАрдбреАрдбреА рдкрд░реАрдХреНрд╖рдг рдпрд╛ рд╡рд┐рдзрд┐ рдЬреИрд╕реА рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдмреАрдбреАрдбреА рдХреЗ рд▓рд┐рдП рдпрд╣ рдПрдХ рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдФрд░ рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рд╣реИрдВред рдЗрд╕ рддрдХрдиреАрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд╣рдмреНрд░ рдкрд░ рдкрд╣рд▓реЗ рд╣реА рдмрд╛рдд рдХреА рдЬрд╛ рдЪреБрдХреА рд╣реИ:
рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг JUnit рдФрд░ TestNG рджреЛрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ BDD рдХреЗ рд▓рд┐рдП рд╕рд┐рд▓рд╡рд╛рдпрд╛ рдЧрдпрд╛ рдЕрдиреНрдп рдЙрдкрдХрд░рдг рд╣реИрдВред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рдврд╛рдВрдЪреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ред рдЗрд╕реЗ
рд╕реНрдкреЙрдХ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рди рдХреЗрд╡рд▓ рдмреАрдбреАрдбреА рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреА рд╣реИ, рдмрд▓реНрдХрд┐
рдЧреНрд░реВрд╡реА рдХреЗ рдлрд╛рдпрджреЗ рднреА рд╣реИрдВред рд╣рд╛рдВ, рд╣рд╛рдВ, рдЧреНрд░реВрд╡реАред рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЧреНрд░реВрд╡реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЬрд╛рд╡рд╛ рдХреЛрдб рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЙрдкрдпреЛрдЧ рдХреЗ рдЙрджрд╛рд╣рд░рдг рд╕реНрдкреНрд░рд┐рдВрдЧ, рдЧреНрд░реЗрд▓реНрд╕, рдЯреЗрдкреЗрд╕реНрдЯреНрд░реА 5 рд╣реИрдВред рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ? рдлрд┐рд░ рдкрдврд╝реЗред
рд╡реНрдпрд╡рд╣рд╛рд░-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╡рд┐рдХрд╛рд╕
рддреЛ, рдореИрдВ рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛рддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред рдХреНрдпрд╛ рдХреЛрдИ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╣реИ рдЬреЛ рдЪреАрдВрдЯреА рдкреИрдЯрд░реНрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреА рд╣реИ (рдпреЗ рдлрд╛рдЗрд▓реЗрдВ рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИрдВ)? - рдХреЛрдИ 1 рдФрд░ рдХреЗрд╡рд▓ 1 рд╡рд░реНрдг, * - рдХрд┐рд╕реА рднреА рд╡рд░реНрдг рдХреА рдХреЛрдИ рднреА рд╕рдВрдЦреНрдпрд╛, ** - рдХреЛрдИ рднреА рдкрдеред рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
public abstract class PathUtils { public static boolean matchAntPath(final String path, final String pattern) {
рджреЛрдиреЛрдВ рд╡рд┐рдзрд┐рдпрд╛рдВ рдпрд╣
рдЬрд╛рдВрдЪрддреА рд╣реИрдВ рдХрд┐ рдкрд╛рд░рд┐рдд рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкреИрдЯрд░реНрди рд╕реЗ рдореЗрд▓ рдЦрд╛рддреА рд╣реИ рдпрд╛ рдирд╣реАрдВ, рд▓реЗрдХрд┐рди
рдореИрдЪрдЕрдирдЯреИрдВрдЯ рд╡рд┐рдзрд┐
рдХреЗрд╡рд▓ рд╕реНрдерд╛рдиреАрдп рдкреИрдЯрд░реНрди рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд┐рдП рдмрд┐рдирд╛ рдкрде рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреА рд╣реИ,
рдореИрдЪрдСрдирдкреИрде рдкреВрд░рд╛ рд░рд╛рд╕реНрддрд╛ рд▓реЗрддрд╛ рд╣реИред рдЯреАрдбреАрдбреА рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЗ рдмрд╛рдж, рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд░реАрдХреНрд╖рдг рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдХреЗ рдХреБрдЫ рд╕реЗрдЯ рдФрд░ рдЕрдкреЗрдХреНрд╖рд┐рдд рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рдХреБрдЫ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
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); } }
рд╢рд╛рдпрдж рдЕрдкрд╡рд╛рджреЛрдВ рдХреЛ рдлреЗрдВрдХреЗ рдЬрд╛рдиреЗ рдкрд░ рдЧрд▓рдд рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЛ рднреА рдпрд╣рд╛рдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛ред рдЕрдм рдЗрд╕реЗ рдмреАрдбреАрдбреА рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ рджреЗрдЦрддреЗ рд╣реИрдВред
рдПрдХ рдкрд░реАрдХреНрд╖рдг рд╕рд┐рд░реНрдл рдПрдХ рдкрд░реАрдХреНрд╖рд╛ рдирд╣реАрдВ рд╣реИ, рдмрд▓реНрдХрд┐ рдПрдХ рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рд╣реИ, рдФрд░ рдЗрд╕рдореЗрдВ рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХрд╛ рд╕рдорд╛рд╡реЗрд╢ рд╣реИред
PathUtils рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ
рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд░реЗрдВ :
- рдкреНрд░рддреАрдХ? рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреА рдЬрд╛рдБрдЪ рдХреА рдЬрд╛ рд░рд╣реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдХрд┐рд╕реА рднреА рд╡рд░реНрдг рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП
- рдкреНрд░рддреАрдХ? рдЯреЗрдореНрдкрд▓реЗрдЯ рдЪреЗрдХ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ 1 рдФрд░ рдХреЗрд╡рд▓ 1 рд╡рд░реНрдг рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП
- рдкреИрдЯрд░реНрди рдореЗрдВ * рдЪрд░рд┐рддреНрд░ рдХреА рдЬрд╛рдБрдЪ рдХреА рдЬрд╛ рд░рд╣реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдХрд┐рд╕реА рднреА рд╡рд░реНрдг рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП
- рдкреИрдЯрд░реНрди рдореЗрдВ * рдЪрд░рд┐рддреНрд░ рдХреА рдЬрд╛рдБрдЪ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рдХрд┐рд╕реА рднреА рд╡рд░реНрдг рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП
- рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдФрд░ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреА рдЬрд╛рдБрдЪ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдорд╛рди рд╢реВрдиреНрдп рдирд╣реАрдВ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдП
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдкреНрд░рддреНрдпреЗрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреА рдЕрдкрдиреА рд╕рддреНрдпрд╛рдкрди рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣реЛрддреА рд╣реИ, рдЖрдорддреМрд░ рдкрд░ рджреА рдЧрдИ рд╢рд░реНрддреЛрдВ рдХреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рджрд┐рдпрд╛ - рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреА рд╢реБрд░реБрдЖрдд рдХреЗ рд▓рд┐рдП рд╕реЗрдЯрд┐рдВрдЧреНрд╕, рдЬрдм - рдХрд╛рд░рдг, рддрдм - рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП рд╢рд░реНрддред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
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 рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХред
рдореБрдЦреНрдп рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ
рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдХрд╣рд╛, рдЧреНрд░реВрд╡реА рдореЗрдВ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓рд┐рдЦреА рдЬрд╛рддреА рд╣реИрдВред рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реИ рдпрд╛ рдмреБрд░рд╛? рдЕрдкрдиреЗ рд▓рд┐рдП рдирд┐рд░реНрдгрдп рд▓реЗрдВ, рд╢реБрд░реБрдЖрддреА
15 рдорд┐рдирдЯ рдореЗрдВ рдЧреНрд░реВрд╡реА рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ
- рдПрдХ рддреНрд╡рд░рд┐рдд рдЕрд╡рд▓реЛрдХрди ред
рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдХреЛ
spock.lang.Specification рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕рдореЗрдВ рдлрд╝реАрд▓реНрдбреНрд╕, рдлрд╝рд┐рдХреНрдЪрд░ рдореЗрдердб, рдлреАрдЪрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ, рд╣реЗрд▓реНрдкрд░ рдореЗрдердб рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред
рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рдлрд╝реАрд▓реНрдб рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдмреАрдЪ рд╕рд╛рдЭрд╛ рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИрдВ, рдЕрд░реНрдерд╛рдд рдПрдХ рдкрд░рд┐рджреГрд╢реНрдп рд╕реЗ рдлрд╝реАрд▓реНрдб рдкрд░рд┐рд╡рд░реНрддрди рджреВрд╕рд░реЗ рдкрд░рд┐рджреГрд╢реНрдп рд╕реЗ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрдЧрд╛ред рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк
@ рд╢реЗрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдиреЛрдЯреЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╕реНрдерд╛рдкрдирд╛ рдХреЗ рддрд░реАрдХреЗ рд╣реИрдВ:
- рд╕реЗрдЯрдЕрдк () - JUnit рдореЗрдВ @Before рдХрд╛ рдПрдирд╛рд▓реЙрдЧ, рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реЗ рдкрд╣рд▓реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд
- рдХреНрд▓реАрдирдЕрдк () - JUnit рдореЗрдВ @After рдХрд╛ рдПрдирд╛рд▓реЙрдЧ, рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдмрд╛рдж рдирд┐рд╖реНрдкрд╛рджрд┐рдд
- setupSpec () - JUnit рдореЗрдВ @BeforeClass рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ, рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдореЗрдВ рдкрд╣рд▓реА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реЗ рдкрд╣рд▓реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд
- CleanupSpec () - JUnit рдореЗрдВ @AfterClass рдХрд╛ рдПрдирд╛рд▓реЙрдЧ, рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдореЗрдВ рдЕрдВрддрд┐рдо рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдмрд╛рдж рдирд┐рд╖реНрдкрд╛рджрд┐рдд
рдЕрдиреНрдп рдкрд░реАрдХреНрд╖рдг рд░реВрдкрд░реЗрдЦрд╛рдУрдВ рдХреА рддрд░рд╣, рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рдЗрдВрд╕реНрдЯреЙрд▓реЗрд╢рди рдХреЛрдб рд▓рд┐рдЦрдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдХрд╛ рдореБрдЦреНрдп рднрд╛рдЧ рд╣реИред рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдБ рдШрдЯрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд▓рд┐рдЯрд░рд▓реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдиреНрд╣реЗрдВ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдерд╛рдЧрдд рд╣реИ, рдФрд░ рдЖрдк рдХрд┐рд╕реА рднреА рд╡рд░реНрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдореБрдЦреНрдп рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдирд╛рдо рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреНрдпрд╛ рдХрд░рддреА рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ:
class PathUtilsSpec extends Specification { def "? character should mean any character"() {
рдкреНрд░рддреНрдпреЗрдХ рдкрд░рд┐рджреГрд╢реНрдп рдореЗрдВ рдмреНрд▓реЙрдХ рд╣реЛрддреЗ рд╣реИрдВ, рдЬреЛ рд▓реЗрдмрд▓ рджреНрд╡рд╛рд░рд╛ рдЗрдВрдЧрд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ:
- рд╕реЗрдЯрдЕрдк рд╕реЗрдЯрдЕрдк () рд╕реНрдерд╛рдкрдирд╛ рд╡рд┐рдзрд┐ рдХреЗ рд╕рдорд╛рди рд╣реИ, рдХреЗрд╡рд▓ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд░рд┐рджреГрд╢реНрдп рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред рд╢реЗрд╖ рдмреНрд▓реЙрдХреЛрдВ рд╕реЗ рдкрд╣рд▓реЗ рд╕реНрдерд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рджреЛрд╣рд░рд╛рдпрд╛ рдирд╣реАрдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╕реЗрдЯрдЕрдк рд▓реЗрдмрд▓ рдЧрд╛рдпрдм рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЖрдк рд╕реЗрдЯрдЕрдк рдХреЗ рдмрдЬрд╛рдп рджрд┐рдП рдЧрдП рднреА рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ рдмреЗрд╣рддрд░ рдкрдардиреАрдпрддрд╛ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдЬрдм-рддрдм-рддрдм)
- рдХреНрд▓реАрдирдЕрдк рдХреНрд▓реАрдирдЕрдк () рд╡рд┐рдзрд┐ рдХреЗ рд╕рдорд╛рди рд╣реИ, рдХреЗрд╡рд▓ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдЕрдВрдд рдореЗрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд╣рд╛рдБ рдмреНрд▓реЙрдХ рд╕реЗ рдкрд╣рд▓реЗ, рдпрджрд┐ рдХреЛрдИ рд╣реЛ, рдФрд░ рджреЛрд╣рд░рд╛рдпрд╛ рдирд╣реАрдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП
- рдЬрдм-рддрдм рдирд┐рд╖реНрдкрд╛рджрди рдХрд╛ рдХрд╛рд░рдг рдФрд░ рд╢рд░реНрдд рд╣реИред рдЬрдм рднрд╛рдЧ рдореЗрдВ, рдЪрд░ рдХреЛ рдЖрдо рддреМрд░ рдкрд░ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдп рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рднрд╛рдЧ рдореЗрдВ рддрдм рдХреБрдЫ рд╢рд░реНрддреЛрдВ рдХреА рдЬрд╛рдБрдЪ рдХреА рдЬрд╛рддреА рд╣реИред рдпрд╣ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреА рдЬрд╛рдБрдЪ, рдЕрдкрд╡рд╛рдж рдХреЗ рдлреЗрдВрдХрдиреЗ рдХреА рдЬрд╛рдБрдЪ, рдпрд╛ рдирдХрд▓реА рд╡рд╕реНрддреБрдУрдВ рдкрд░ рдЕрдорд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рддрд░реАрдХреЛрдВ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред рдЗрд╕ рдмреНрд▓реЙрдХ рдХреЛ рджреЛрд╣рд░рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдврд╛рдВрдЪреЗ рдХреЗ рд▓реЗрдЦрдХ рдЗрд╕рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реЛрдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддреЗ рд╣реИрдВ, рдПрдХ рдЕрдЪреНрдЫреА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ 1 рд╕реЗ 5 рдРрд╕реЗ рдмреНрд▓реЙрдХ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдП
- рдЕрдкреЗрдХреНрд╖рд╛ рддрдм рдПрдХ рд╕рд░рд▓реАрдХреГрдд рд╣реИ рдЬрдм-рддрдм рдмреНрд▓реЙрдХ рдХрд░реЗрдВ рдЬрд╣рд╛рдВ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдФрд░ рд╕рддреНрдпрд╛рдкрди рдПрдХ рд╣реА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдореЗрдВ рд╣реИрдВ
- рдЬрд╣рд╛рдБ TestNG рд╕реЗ @DataProvider рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИ, рдЬрд┐рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рд╕реЗрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ
рдЕрдм рд╕рдм рдХреБрдЫ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗред рдПрдХ рдЕрдиреНрдп рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред
PathSearcher , рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛, рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЪреАрдВрдЯреА рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
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() } }
рддреЛ, рдпрд╣ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ - рдПрдХ рдЦреЛрдЬ рдЗрдВрдЬрди рдЬреЛ
рдХреНрд▓рд╛рд╕ 1 рд╕реЗ
рдЯреЗрд╕реНрдЯ 1 рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдЦреЛрдЬ рдХрд░рддрд╛ рд╣реИ, рдЦреЛрдЬ, рдирд┐рд╖реНрдкрд╛рджрди рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ - рдЦреЛрдЬ рдЗрдВрдЬрди рдХреЛ рд╣рдорд╛рд░реА рдлрд╛рдЗрд▓реЗрдВ рдвреВрдВрдврдиреА рдЪрд╛рд╣рд┐рдПред
inClasspath рдПрдХ рд╕рд╣рд╛рдпрдХ рд╡рд┐рдзрд┐ рд╣реИ рдЬреЛ
classpath рд╕реЗ рдирд┐рд░рдкреЗрдХреНрд╖ рдлрд╝рд╛рдЗрд▓ рдкрде рд▓реМрдЯрд╛рддреА рд╣реИред
PathUtils рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреНрдп рдЙрджрд╛рд╣рд░рдг "рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рдореВрд▓реНрдп рдФрд░ рдЬрд╛рдБрдЪ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдЕрд╢рдХреНрдд рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП"
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) } }
рдпрд╣рд╛рдВ рд╣рдо
рдлреЗрдВрдХрд╛ рд╣реБрдЖ (...) рддрд░реАрдХрд╛ рджреЗрдЦрддреЗ рд╣реИрдВ, рдпрд╣ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЕрдкрд╡рд╛рдж рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рд╣реИ,
рдиреЛрдЯрдЯреНрд░реЙрди (...) рд╡рд┐рдзрд┐ рдФрд░
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") } }
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЙрджрд╛рд╣рд░рдг рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЕрдЧрд░
рдХрдм рдФрд░
рдлрд┐рд░ рджреЛрдиреЛрдВ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рдПрдХ рд╣реА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рддреЛ
рдЙрдореНрдореАрдж рдмреНрд▓реЙрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред
рдЬрд╣рд╛рдБ рдмреНрд▓реЙрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рдкрд░рд┐рдЪрд╛рд▓рдирд╛рддреНрдордХ рдмрдирд╛рдХрд░ рдЗрд╕ рдкрд░рд┐рджреГрд╢реНрдп рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
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") } }
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрджрд╛рд╣рд░рдгреЛрдВ рд╕реЗ рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЗрд╕ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ред рдореИрдВ рд╕рд┐рд░реНрдл рдЗрд╕ рдмрд╛рдд рдкрд░ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдЖрдк рдЙрд╕ рдмреНрд▓реЙрдХ рдореЗрдВ рдЙрди рдлрд╝реАрд▓реНрдбреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рдЬреЛ
@Sared рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдирд╣реАрдВ рд╣реИрдВред
рдмрд╛рддрдЪреАрдд
рдЕрдиреНрдп рдмрд╛рддреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд░реВрдкрд░реЗрдЦрд╛ рдЖрдкрдХреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рдмрд┐рдирд╛ рдирдХрд▓реА рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рдЖрдк рдЗрдВрдЯрд░рдлреЗрд╕ рдФрд░ рдЧреИрд░-рдЕрдВрддрд┐рдо рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдореЛрдХрд╛ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рд░рдЪрдирд╛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддреА рд╣реИ:
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() }
рдмрд╛рддрдЪреАрдд рд╕реНрдерд╛рдиреАрдп (
рддрддреНрдХрд╛рд▓реАрди рдмреНрд▓реЙрдХ рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд) рдФрд░ рд╡реИрд╢реНрд╡рд┐рдХ (рдЕрдиреНрдпрддреНрд░ рдкрд░рд┐рднрд╛рд╖рд┐рдд) рд╣реИрдВред рд╕реНрдерд╛рдиреАрдп рдХреЗрд╡рд▓
рддрддреНрдХрд╛рд▓реАрди рдмреНрд▓реЙрдХ рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИрдВ, рд╡реИрд╢реНрд╡рд┐рдХ рд╣рд░ рдЬрдЧрд╣ рдЙрдкрд▓рдмреНрдз рд╣реИрдВ, рдЙрдирдХреА рдкрд░рд┐рднрд╛рд╖рд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ред рд╕реНрдерд╛рдиреАрдп рдЗрдВрдЯрд░реИрдХреНрд╢рди рдХреЗ рд▓рд┐рдП, рдЖрдк рдЙрдирдХреА рд╢рдХреНрддрд┐ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ рд╡рд┐рдзрд┐ рдХреЙрд▓ рдХреА рдЕрдкреЗрдХреНрд╖рд┐рдд рд╕рдВрдЦреНрдпрд╛ рд╣реИред
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 рдСрдмреНрдЬреЗрдХреНрдЯ
рдмрдирд╛рддреЗ рд╣реИрдВ ред рдлрд┐рд░ рд╣рдо рдирд╛рдо (
рдЬрдм- рдмреНрд▓реЙрдХ) рдХреЗ рджреНрд╡рд╛рд░рд╛ рдХрдИ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдЦреЛрдЬрддреЗ рд╣реИрдВ рдФрд░ рдЕрдВрдд рдореЗрдВ рдЬрд╛рдБрдЪрддреЗ рд╣реИрдВ рдХрд┐
рдЦреЛрдЬрд╛ рдЧрдпрд╛ рддрд░реАрдХрд╛ рдЬреЛ рддреИрдпрд╛рд░ рдкрд░рд┐рдгрд╛рдо рджреЗрддрд╛ рд╣реИ рдЙрд╕реЗ рдХреЗрд╡рд▓ 1 рдмрд╛рд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред
рдмрд╛рддрдЪреАрдд рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реБрдП, рдЖрдк рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
1 * dao.findAll() >> users (1..4) * dao.findAll() >> users (2.._) * dao.findAll() >> users (_..4) * dao.findAll() >> users _.findAll() >> users dao./find.*/(_) >> users
рдпрд╣рд╛рдБ рдФрд░ рдкрдврд╝реЗрдВ
рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдврд╛рдВрдЪреЗ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрд╣реБрдд рд╕рд╛рд░реА рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЕрдиреНрдп рд░реВрдкрд░реЗрдЦрд╛рдУрдВ рдХреА рддрд░рд╣, рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЗ рд╡рд┐рд╕реНрддрд╛рд░ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╣реИрдВ:
- @ рдЯрд╛рдЗрдордЖрдЙрдЯ - рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрддрдо рдЯрд╛рдЗрдордЖрдЙрдЯ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, 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) } }
рдЕрдиреНрдп рдврд╛рдВрдЪреЗ рдХреЗ рд╕рд╛рде рдПрдХреАрдХрд░рдг рдЕрд▓рдЧ-рдЕрд▓рдЧ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдХрд┐рдП рдЧрдП рд╣реИрдВ:
- рд╕реНрдкреНрд░рд┐рдВрдЧ - рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ @ContextConfiguration (рд╕реНрдерд╛рди = "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 (рдЯреЗрдкреЗрд╕реНрдЯреНрд░реА_рдореЙрдбреНрдпреВрд▓_рдХреНрд▓рд╛рд╕) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдиреЛрдЯреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ @ рдЗрдВрдЬреЗрдХреНрдЯ рдПрдиреЛрдЯреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдлрд╝реАрд▓реНрдб рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
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 рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рджреВрд╕рд░рд╛ рдкрд╣рд▓реЗ рд╕реЗ рдЙрдкрд▓рдмреНрдз рд╣реИ, рдореВрд▓ (рдЕрдиреБрдорд╛рдирд┐рдд) рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ
- IGlobalExtension - рдЖрдкрдХреЛ рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдореЗрдЯрд╛рдбреЗрдЯрд╛ ( SpecInfo ) рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдпрд╣рд╛рдВ рдЖрдк рдХрд┐рд╕реА рднреА рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдШрдЯрдХреЛрдВ (рдлрд╝реАрд▓реНрдбреНрд╕, рд╕реНрдерд╛рдкрдирд╛ рд╡рд┐рдзрд┐рдпреЛрдВ, рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рд╕реНрдХреНрд░рд┐рдкреНрдЯ) рдХреЗ рд▓рд┐рдП рдореЗрдЯрд╛рдбреЗрдЯрд╛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░ рдЙрдиреНрд╣реЗрдВ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред
- IAnnotationDrivenExtension - рдкрд┐рдЫрд▓реЗ рд╡рд╛рд▓реЗ рдХреЗ рд╕рдорд╛рди, рдХреЗрд╡рд▓ рдХрд╛рд░реНрдп рдХреЛ рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ, рдпрджрд┐ рд╣рдорд╛рд░рд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдПрдиреЛрдЯреЗрд╢рди рд╕реЗ рдмрдВрдзрд╛ рд╣реБрдЖ рд╣реИ, рддреЛ рдЖрдк рдХрд╛рд░реНрдп рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП AbstractAnnotationDrivenExtension рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ
рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ
IGlobalExtension рдпрд╛
IAnnotationDrivenExtension рд╡рдВрд╢рдЬ рд╡рд░реНрдЧ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдЖрдкрдХреЗ
IMethodInterceptor рдХреЛ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдШрдЯрдХреЛрдВ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░
рдЕрдВрдд рдореЗрдВ ,
рдореЗрдЯрд╛ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЛ
META-INF / Services / org.spockframework.runtime.extension.IGlobal рдореЗрдВ рдЬреЛрдбрд╝ рджреЗрдВред ,
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 } }
рдкрд░реАрдХреНрд╖рдг рдЪрд▓ рд░рд╣рд╛ рд╣реИ
рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рдХрд┐ рд╕реНрдкреЙрдХ рдкрд░реАрдХреНрд╖рдг JUnit Launcher (
рд╕реНрдкреБрддрдирд┐рдХ ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЪрд▓рд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ, рд╡реЗ рд╡рд┐рднрд┐рдиреНрди рдЖрдИрдбреАрдИ рдХреЗ рддрд╣рдд рдареАрдХ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ (рдЬреИрд╕рд╛ рдХрд┐ рд▓реЗрдЦрдХ рдХрд╣рддреЗ рд╣реИрдВ, рдореИрдВрдиреЗ рдХреЗрд╡рд▓ рд╡рд┐рдЪрд╛рд░ рдХреЗ рддрд╣рдд рдЬрд╛рдВрдЪ рдХреА)ред рдЖрдк рдЪреАрдВрдЯреА, рдорд╛рд╡реЗрди, рдЧреНрд░реЗрдбреЗрд▓ рд╕реЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рдкреНрд░рдХреНрд╖реЗрдкрдг рдХреЛ рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА
рдпрд╣рд╛рдВ рдкрд╛рдИ рдЬрд╛ рд╕рдХрддреА
рд╣реИ ред
рдореИрдВ рдЕрдкрдиреЗ рд▓рд┐рдП рдпрд╣ рдЬреЛрдбрд╝реВрдВрдЧрд╛, рдореИрдВрдиреЗ рдорд╛рд╡реЗрди рдХреЗ рддрд╣рдд рд╡рд┐рдиреНрдпрд╛рд╕ рдХреЛ рдереЛрдбрд╝рд╛ рдмрдврд╝рд╛ рджрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рд▓реЗрдЦрдХреЛрдВ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд 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>
рдирд┐рд╖реНрдХрд░реНрд╖
рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдореИрдВ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдЗрд╕ рдЕрджреНрднреБрдд рдврд╛рдВрдЪреЗ рд╕реЗ рдорд┐рд▓рд╛, рдореБрдЭреЗ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рдЕрдиреБрднрд╡ рдирд╣реАрдВ рд╣реИ, рдореИрдВ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдХреЗ рд╕рд╛рде рдХрд╣ рд╕рдХрддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдХреНрд╖рдорддрд╛рдУрдВ рдореЗрдВ рд╣реАрди рдирд╣реАрдВ рд╣реИ, рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдХреБрдЫ рдкрд╣рд▓реБрдУрдВ рдореЗрдВ рдЕрдиреНрдп рд░реВрдкрд░реЗрдЦрд╛рдУрдВ рдХреЛ рдкрд╛рд░ рдХрд░рддрд╛ рд╣реИред рдореБрдЭреЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЧреНрд░реВрд╡реА рдкрд░ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рдкрд╕рдВрдж рдерд╛, рдореБрдЭреЗ рдмреАрдбреАрдбреА рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рдкрд╕рдВрдж рдерд╛ред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЖрдкрдХреЛ рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред
рдЙрджрд╛рд╣рд░рдг
рдпрд╣рд╛рдВ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ
рд╣реИрдВ ред
рд╕рд╛рд╣рд┐рддреНрдп