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

mockgenによるモック生成を高速化するツール bulkmockgenのご紹介 / Kyoto.go #43

mockgenによるモック生成を高速化するツール bulkmockgenのご紹介 / Kyoto.go #43

utagawa kiki

July 14, 2023
Tweet

More Decks by utagawa kiki

Other Decks in Programming

Transcript

  1. mockgenによるモック生成を
    高速化するツール
    bulkmockgenのご紹介
    Kyoto.go #43 @utgwkk (うたがわきき)

    View Slide

  2. 自己紹介
    @utgwkk (うたがわきき)
    株式会社はてな
    Webアプリケーションエンジニア in 京都
    最近はGoを書いて暮らしています

    View Slide

  3. みなさん
    モックしていますか?

    View Slide

  4. gomock (mockgen)
    https://github.com/uber/mock
    (最近 https://github.com/golang/mock がarchiveされた)
    mockgenでモックを生成してテストで使う

    View Slide

  5. mockgenを使ったモック世界観 (1)
    // interfaceを定義して
    type UserStore interface {
    FindById(ctx context.Context, id string) (*model.User,
    error)
    }
    // モックを生成する
    //go:generate mockgen -package mock_store -destination
    mock_store/user_store.go . UserStore

    View Slide

  6. mockgenを使ったモック世界観 (2)
    // モックを注入する
    ctrl := gomock.NewController(t)
    m := mock_repo.NewMockUserStore(ctrl)
    s := NewUserService(s)
    // モックが呼び出される方法を表明する
    m.EXPECT().FindById(gomock.Any(), "user").
    Return(&model.User{Id: "user"}, nil)
    // モックを使うメソッドを呼び出してテストする
    ctx := context.Background()
    u, err := s.FindUserById(ctx, "user")

    View Slide

  7. mockgen便利
    モック生成を一手に引き受けてくれる
    便利なmatcherがある (gomock.Any(), gomock.InAnyOrder(), …)
    呼び出し方が不正だったらテストを落としてくれる

    View Slide

  8. mockgenの課題
    go generateが直列に実行されるので遅い
    reflect modeだと都度コンパイルされるので遅い

    View Slide

  9. モック生成コマンドが多くなると遅い
    //go:generate mockgen -package mock_store -destination
    mock_store/a.go . StoreA
    //go:generate mockgen -package mock_store -destination
    mock_store/b.go . StoreB
    //go:generate mockgen -package mock_store -destination
    mock_store/c.go . StoreC
    go generateによるコード生成は直列に実行される
    Proposal: cmd/go: parallel execution of //go:generate · Issue #20520 · golang/go

    View Slide

  10. mockgenのreflect modeの仕組み上遅い
    モックするinterfaceの情報を得るためにGoのプログラムをコンパイルしている
    mockgenを実行したらコンパイルが走る!!

    View Slide

  11. どんどん遅くなるgo generate
    77.70s user 39.76s system 143% cpu 1:21.75 total

    View Slide

  12. https://xkcd.com/303/

    View Slide

  13. go:generate をまとめることはできるが
    //go:generate mockgen -package mock_store -destination
    mock_store/store.go . StoreA,StoreB,StoreC
    人間がこの1行を編集しまくる必要がある?
    うまくコンフリクトを解消できる??

    View Slide

  14. bulkmockgen
    https://github.com/utgwkk/bulkmockgen
    mockgenのコード生成を1回にまとめて高速化するツールbulkmockgenを作った - 私が
    歌川です
    モック対象のinterfaceをスライスに列挙して一度にコード生成する
    移行ツールもある (mockgen-to-bulkmockgen)

    View Slide

  15. 仕組み
    モック対象のinterfaceをスライスに列挙する
    静的解析 (go/parser, go/ast) でinterfaceのリストを取得する
    スライスに渡したinterface名を結合してmockgenに渡す

    View Slide

  16. デモ
    大量のinterface定義に対するモック生成を一括で行う
    https://github.com/utgwkk/bulkmockgen/tree/main/benchmark/interfaces
    (カンペ: VSCodeを開いてください)

    View Slide

  17. コード生成を速くして効率を上げることに成功
    77.70s user 39.76s system 143% cpu 1:21.75 total (before)
    52.18s user 19.93s system 209% cpu 34.397 total (after)
    関わっているプロジェクトで47秒ほど高速化できた

    View Slide

  18. 課題
    mockgenが生成するコード中のコメントがコンフリクトする!!
    // Code generated by MockGen. DO NOT EDIT.
    // Source: example.com/test/repo (interfaces: IFoo,IBar,IBaz…)

    View Slide

  19. workaround
    go generateしたあとにコメントを消す
    for go_file in `git grep --name-only '^// Code generated by MockGen. DO NOT
    EDIT.' -- '*.go'`; do
    perl -i -nlpe '$_="" if m{// Source: example.com/test/repo}' $go_file
    gofmt -w $go_file
    done

    View Slide

  20. まとめ
    mockgenによるコード生成をまとめるツールbulkmockgenをご紹介
    複数のinterfaceのモックを一度に生成することでコード生成を高速化できた
    interface一覧を1行にまとめる必要がないので人間に優しい

    View Slide

  21. 参考
    ● mockgenのコード生成を1回にまとめて高速化するツールbulkmockgenを作った -
    私が歌川です
    ● gomockを完全に理解する
    ● go generateに関するproposal
    ○ Proposal: cmd/go: parallel execution of //go:generate · Issue #20520 ·
    golang/go
    ○ proposal: cmd/go: generate allow arguments to span multiple lines ·
    Issue #46050 · golang/go

    View Slide

  22. 先行研究: gomockhandler
    Goで大量のモックをより統一的に管理し、もっと高速に生成したい!そうだ!!
    gomockhandlerを使おう!! | メルカリエンジニアリング
    mockgenコマンドを並列実行する
    go generateではなく独自CLIによるモック管理

    View Slide

  23. なぜbulkmockgenを作ったのか
    go generateの仕組みに乗ったまま高速化できないか考えた
    既存の仕組みからジャンプが少ないと導入しやすい
    モックしたいinterfaceをGoのコードとして列挙するのでrenameにも強い

    View Slide

  24. 構想
    gomockhandlerとbulkmockgenを組み合わせることができると爆速でモックを生成でき
    るのでは??

    View Slide