Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dive into gomock / Go Conference 2024

Dive into gomock / Go Conference 2024

utagawa kiki

June 08, 2024
Tweet

More Decks by utagawa kiki

Other Decks in Programming

Transcript

  1. テストを書くには? s := NewBlogService(...) // UserStore.FindUserById メソッドが、 // (*, model.UserId("user"))

    という引数で呼ばれることを期待 し、 // 呼ばれたら (&model.User{}, nil) を返す。 // もしメソッド呼び出しがなければテストは失敗する。 blog, err := s.RegisterNewBlog(...)
  2. go.uber.org/mock (gomock) • https://github.com/uber-go/mock • モックフレームワーク ◦ mockgen (後述) で生成したinterfaceのモック実装と

    組み合わせて使う • もともとはGoogleがメンテナンスしていた ◦ Uberがメンテナを引き継いだ
  3. gomockでテストを書く ctrl := gomock.NewController(t) m := mock_repo.NewMockUserStore(ctrl) s := NewBlogService(m,

    ...) m.EXPECT(). FindUserById(gomock.Any(), model.UserId("user")). Return(&model.User{}, nil) blog, err := s.RegisterNewBlog(...)
  4. gomockでテストを書く (再掲) ctrl := gomock.NewController(t) m := mock_repo.NewMockUserStore(ctrl) s :=

    NewBlogService(m, ...) m.EXPECT(). FindUserById(gomock.Any(), model.UserId("user")). Return(&model.User{}, nil) blog, err := s.RegisterNewBlog(...)
  5. テスト失敗時の出力例 user.go:103: Unexpected call to *user_test.MockIndex.Put([a 1]) at user.go:103 because:

    expected call at user_test.go:17 doesn't match the argument at index 0. Got: a (string) Want: is equal to c (string)
  6. 組み込みのMatcher • Any() • Nil() • Eq(x any) • All(ms

    ...Matcher) • AnyOf(xs ...any) • Len(i int) • Not(x any) • Cond(fn func(x any) bool) • AssignableTypeOf(x any) • InAnyOrder(x any) • Regex(regexStr string)
  7. 組み込みのMatcher • All(ms ...Matcher) ◦ 引数に渡したMatcher全てが受理するなら受理する • AnyOf(xs ...any) ◦

    引数のいずれかに一致するなら受理する • Len(i int) ◦ 引数のlenが一致するなら受理する
  8. 組み込みのMatcher • Not(x any) ◦ 引数がxでないなら受理する • Cond(fn func(x any)

    bool) ◦ 引数をfnに渡してtrueが返るなら受理する ◦ 任意の条件が書ける • AssignableTypeOf(x any) ◦ 引数が型xに代入可能なら受理する
  9. 組み込みのMatcher • InAnyOrder(x any) ◦ 引数がxの要素の順序を無視して一致するなら受理す る • Regex(regexStr string)

    ◦ 引数が正規表現regexStrにマッチする文字列もしくは バイト列なら受理する
  10. Matcherの実装例: Len(i int) • 引数のlenを確かめる Matcher • 引数をreflect.Valueに変換 する •

    lenが取得できるなら ◦ lenが期待した値と一致する ことを確かめる • lenが取得できないなら ◦ falseを返す
  11. メソッドの呼び出し回数をテストする • Times(n) ◦ ちょうどn回呼ばれる必要がある • MaxTimes(n) ◦ 最大でn回まで呼ばれてよい •

    MinTimes(n) ◦ 最小でもn回呼ばれる必要がある • AnyTimes() ◦ 何度呼ばれてもよい (呼ばれなくてもよい)
  12. call.After() メソッド • callB.After(callA) ◦ callA が呼ばれた後に callB が呼ばれる •

    呼び出し順を依存グラフとして保持 ◦ 複雑なテストパターンも表現できる
  13. gomockでテストを書く (再掲) ctrl := gomock.NewController(t) m := mock_repo.NewMockUserStore(ctrl) s :=

    NewBlogService(m, ...) m.EXPECT(). FindUserById(gomock.Any(), model.UserId("user")). Return(&model.User{}, nil) blog, err := s.RegisterNewBlog(...)
  14. 分かるようになりましたね? ctrl := gomock.NewController(t) m := mock_repo.NewMockUserStore(ctrl) s := NewBlogService(m,

    ...) m.EXPECT(). FindUserById(gomock.Any(), model.UserId("user")). Return(&model.User{}, nil) blog, err := s.RegisterNewBlog(...)