Spockの基礎

4,604 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,604
On SlideShare
0
From Embeds
0
Number of Embeds
2,730
Actions
Shares
0
Downloads
5
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Spockの基礎

  1. 1. Spockの基礎 @kiy0taka13年3月9日土曜日
  2. 2. 自己紹介 •奥 清隆(おく きよたか) • @kiy0taka、id:kiy0taka •株式会社ニューキャスト所属 •名古屋在住JGGUG関西支部長 •仕事:Groovy/Grailsとか13年3月9日土曜日
  3. 3. spock-shell • シェルスクリプトのテストをSpockで書 くSpock拡張 • http://git.io/spock-shell13年3月9日土曜日
  4. 4. import org.kiy0taka.spock.shell.ShellSpec class GreetingSpec extends ShellSpec { def "greet with custom message"() { given: export GREET, Goodbye when: run greeting.sh, Spock then: lines[0] == Goodbye Spock! } }13年3月9日土曜日
  5. 5. dproofs http://xmldo.jp/dproofs13年3月9日土曜日
  6. 6. Agenda • AST変換 • Specification13年3月9日土曜日
  7. 7. SpockTransform • SpockのAST変換はこっから始まる Spec spec = new SpecParser(errorReporter).build(clazz); spec.accept(new SpecRewriter(nodeCache, sourceLookup, errorReporter)); spec.accept(new SpecAnnotator(nodeCache));13年3月9日土曜日
  8. 8. SpecParser • テストクラスからSpecを組み立てる13年3月9日土曜日
  9. 9. Spec public class Spec extends Node<Spec, ClassNode> { private final List<Field> fields private final List<Method> methods private FixtureMethod initializerMethod private FixtureMethod sharedInitializerMethod private FixtureMethod setupMethod private FixtureMethod cleanupMethod private FixtureMethod setupSpecMethod private FixtureMethod cleanupSpecMethod }13年3月9日土曜日
  10. 10. SpecRewriter • テストクラスの原形がなくなるまで殴 り続ける • 仲間を呼んでボコボコにする13年3月9日土曜日
  11. 11. Rewriter連合 • SpecRewriter • ConditionRewriter • DeepBlockRewriter • InteractionRewriter • WhenBlockRewriter13年3月9日土曜日
  12. 12. AST変換前 import spock.lang.* class HelloSpock extends spock.lang.Specification { def "length of Spocks and his friends names"() { expect: name.size() == length where: name | length "Spock" | 5 "Kirk" | 4 "Scotty" | 6 } }13年3月9日土曜日
  13. 13. import spock.lang.* AST変換後 import org.spockframework.runtime.model.* @SpecMetadata(line = 5, filename = HelloSpock.groovy) public class HelloSpock extends spock.lang.Specification { @FeatureMetadata(parameterNames = [name, length], ...) public void $spock_feature_0_0(name, length) { Object $spock_valueRecorder = new ValueRecorder() SpockRuntime.verifyCondition(...) this.getSpecificationContext().getMockController().leaveScope() } @DataProviderMetadata(line = -1, dataVariables = [name]) public java.lang.Object $spock_feature_0_0prov0() { return [Spock, Kirk, Scotty] } @DataProviderMetadata(line = -1, dataVariables = [length]) public java.lang.Object $spock_feature_0_0prov1() { return [5, 4, 6] } public Object $spock_feature_0_0proc(Object $spock_p0, Object $spock_p1) { Object name = $spock_p0 Object length = $spock_p1 return new Object[] } }13年3月9日土曜日
  14. 14. フィールド def date = new Date() @FieldMetadata(name = date, line = 8, ordinal = 0) private Object date private Object $spock_initializeFields() { date = new Date() }13年3月9日土曜日
  15. 15. @Sharedフィールド @Shared def date = new Date() @Shared @FieldMetadata(name = date, line = 8, ordinal = 0) protected volatile Object $spock_sharedField_date private Object $spock_initializeSharedFields() { $spock_sharedField_date = new java.util.Date() }13年3月9日土曜日
  16. 16. フィーチャー def test something() { expect: 1 == 1 } @FeatureMetadata(parameterNames = [], name = test something, ...) public void $spock_feature_0_0() { Object $spock_valueRecorder = new ValueRecorder() SpockRuntime.verifyCondition(...) this.getSpecificationContext().getMockController().leaveScope() }13年3月9日土曜日
  17. 17. PowerAssert SpockRuntime.verifyCondition( $spock_valueRecorder.reset(), name.size() == length, 9, 9, null, $spock_valueRecorder.record( 5, $spock_valueRecorder.record( 3, $spock_valueRecorder.record(0, name) .$spock_valueRecorder.record(1, size)() ) == $spock_valueRecorder.record(4, length) ) ) ※ GroovyのPowerAssertとは別実装13年3月9日土曜日
  18. 18. thrown() when: def expected = new Calc().add(1, 1) then: thrown(Exception) @FeatureMetadata(parameterNames = [], name = test something, ...) public void $spock_feature_0_0() { Object expected = this.getSpecificationContext().setThrownException(null) try { expected = new Calc().add(1, 1) } catch (Throwable $spock_ex) { this.getSpecificationContext().setThrownException($spock_ex) } finally { } this.thrownImpl(null, null, Exception) this.getSpecificationContext().getMockController().leaveScope() }13年3月9日土曜日
  19. 19. where: expect: expected == actual where: actual | expected 1 | 1 "a" | "a" @FeatureMetadata(parameterNames = [actual, expected], ...) public void $spock_feature_0_0(Object actual, Object expected) { ... } @DataProviderMetadata(line = -1, dataVariables = [actual]) public Object $spock_feature_0_0prov0() { return [1, a] } @DataProviderMetadata(line = -1, dataVariables = [expected]) public Object $spock_feature_0_0prov1() { return [1, a] }13年3月9日土曜日
  20. 20. Mock() given: def foo = Mock(Foo) when: foo.add(1, 2) then: 1 * foo.add(_, _) Object foo = this.MockImpl(foo, null, Foo) this.getSpecificationContext().getMockController().enterScope() this.getSpecificationContext().getMockController().addInteraction( new InteractionBuilder(16, 9, 1 * foo.add(_, _)) .setFixedCount(1) .addEqualTarget(foo) .addEqualMethodName(add) .setArgListKind(true) .addEqualArg(_) .addEqualArg(_) .build()) foo.add(1, 2) this.getSpecificationContext().getMockController().leaveScope() this.getSpecificationContext().getMockController().leaveScope()13年3月9日土曜日
  21. 21. あとは各自 見ておくように!13年3月9日土曜日
  22. 22. AST変換の確認方法 ⌘T13年3月9日土曜日
  23. 23. Specification13年3月9日土曜日
  24. 24. Specification @RunWith(Sputnik.class) public abstract class Specification extends MockingApi { ... }13年3月9日土曜日
  25. 25. Sputnik • org.junit.runner.Runnerの実装 • SpecInfoBuilder使ってSpecInfoを構築 • ExtensionRunner/ ParameterizedSpecRunnerを使ってテスト 実行13年3月9日土曜日
  26. 26. SpecInfo public class SpecInfo extends ... { List<FieldInfo> fields List<IMethodInterceptor> setupInterceptors List<IMethodInterceptor> cleanupInterceptors List<IMethodInterceptor> setupSpecInterceptors List<IMethodInterceptor> cleanupSpecInterceptors List<IMethodInterceptor> sharedInitializerInterceptors List<IMethodInterceptor> initializerInterceptors List<IRunListener> listeners MethodInfo initializerMethod MethodInfo sharedInitializerMethod List<MethodInfo> setupMethods List<MethodInfo> cleanupMethods List<MethodInfo> setupSpecMethods List<MethodInfo> cleanupSpecMethods List<FeatureInfo> features }13年3月9日土曜日
  27. 27. SpecInfoBuilder#doBuild() private SpecInfo doBuild() { buildSuperSpec(); buildSpec(); buildFields(); buildFeatures(); buildInitializerMethods(); buildFixtureMethods(); return spec; } private void buildSuperSpec() { ... SpecInfo superSpec = new SpecInfoBuilder(superClass, clazz).doBuild(); ... }13年3月9日土曜日
  28. 28. super.setup()しない class SubSpec extends BaseSpec { def setup() { super.setup() ... } } SubSpec.groovy: 9: A base class fixture method should not be called explicitly because it is always invoked automatically by the framework @ line 9, column 9. super.setup() ^ 1 error13年3月9日土曜日
  29. 29. ExtensionRunner • org.junit.runner.Runnerの実装ではない • フィーチャーメソッドの前に Extension(Global/AnnotationDriven)を実行13年3月9日土曜日
  30. 30. JUnit互換? • @Rule/@ClassRuleはRuleExtensionによ って実行される • @Before/@Afterとかフィクスチャーメ ソッドとして扱われる13年3月9日土曜日
  31. 31. ParameterizedSpecRunner • パラメータごとにフィーチャーメソッ ドを実行 • パラメータライズじゃないフィーチャ ーメソッドもこれで実行13年3月9日土曜日
  32. 32. まとめ13年3月9日土曜日
  33. 33. 何得? • AST変換の勉強にはなる • Extensionを作るときに知ってるといい? • 他のExtension実装を見たほうがはやい13年3月9日土曜日

×