Slide 1

Slide 1 text

ΧόϨοδ95%Ҏ্Λ࣮ݱͨ͠ ςετίʔυͷॻ͖ํ גࣜձࣾ)3#SBJO
 ླ໦༔େ

Slide 2

Slide 2 text

ࣗݾ঺հ w ླ໦༔େ w גࣜձࣾ)3#SBJOॴଐ w ޷͖ͳݴ༿ႈ౳ੑ w (P+BWB4DSJQU

Slide 3

Slide 3 text

-ैۀһͷ໨ඪΛ؅ཧͯ͠ ɹɹɹɹධՁ͢ΔͨΊͷΫϥ΢υπʔϧ- https://okr.hrbrain.biz/

Slide 4

Slide 4 text

ૣ଎Ͱ͕͢ɺ

Slide 5

Slide 5 text

Έͳ͞Μςετ͸޷͖Ͱ͔͢?

Slide 6

Slide 6 text

ࢲ͸ݏ͍Ͱ͢

Slide 7

Slide 7 text

ςετΛݏ͍ͳཧ༝ w ΊΜͲ͍͘͞ w ଞਓͷॻ͍ͨςετίʔυΛϝϯςφϯε͢ΔͷͭΒ͍ w ࣮ߦ͢Δͷʹ͕͔͔࣌ؒΔ

Slide 8

Slide 8 text

ࠓ·ͰͷγεςϜͱςετίʔυ

Slide 9

Slide 9 text

γεςϜ֓ཁ w (P w 3%# w .7$෩ͷΞʔΩςΫνϟ

Slide 10

Slide 10 text

DBʹ௚઀ΞΫηε͢Δςετ(ControllerͰ΋) func TestXxx(t *testing.T) { // DBʹςετσʔλΛηοτ͢Δ // ͍͔ͭ͘ͷςετέʔεͰςετ͢Δ // ςετσʔλͷ࡟আ }

Slide 11

Slide 11 text

ಉ࣌ʹ࣮ߦ͢Δͱࣦഊ͢Δςετ w ςετσʔλ͕ڝ߹͠λΠϛϯάʹΑͬͯ͸༧ظͤ͵σʔλ͕ฦ Γςετ͕ࣦഊ͢Δɻɻ

Slide 12

Slide 12 text

ղܾํ๏ go test -parallel 1 ./...

Slide 13

Slide 13 text

ଞͷਓ͕ॻ͍ͨςετ w ਆݒ͔ΓతͳόϥϯεͰ੒Γཱ͍ͬͯΔ w $POUSPMMFSʹۙͮ͘΄Ͳෳࡶ͞͸૿͢ w ΧόϨοδΛݟΔݶΓςετࣗମ͸໰୊ͳ͘͞Ε͍ͯͦ͏ w ผػೳ͕ϦϦʔε͞Εͨͱ͖ʹσάϨ͞Ε͍ͯͳ͍͜ͱͷ֬ೝ͸ Ͱ͖͍ͯΔ͕ɺؔ܎ͨ͠ػೳΛϦϦʔε͍ͨ͠ͱ͖ʹਏ͍ɻ

Slide 14

Slide 14 text

౰࣌ͷϥΠϯΧόϨοδ w ϛυϧ΢ΣΞͳͲେࣄͳͱ͜ΖͰ΋ఔ౓ w શମݟΔͱΛ੾͍ͬͯͨ w ΧόϨοδΛ্͛Α͏ͱࢥͬͯ΋େมͳঢ়ଶ

Slide 15

Slide 15 text

मਖ਼ޙ (Ұ෦·࣮ͩ૷தͷ΋ͷ͕͋Γ·͢)

Slide 16

Slide 16 text

αʔόʔฤ

Slide 17

Slide 17 text

࣮૷࣌ͷϧʔϧΛ͍͔ͭ͘࡞Γ·ͨ͠

Slide 18

Slide 18 text

ΫϦʔϯΞʔΩςΫνϟ https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

Slide 19

Slide 19 text

ΫϦʔϯΞʔΩςΫνϟ w ؔ৺ͷ෼཭ w *OUFSGBDFͷಠཱ w σʔλϕʔεͷಠཱ w ֎෦ػೳͷಠཱ

Slide 20

Slide 20 text

σΟϨΫτϦߏ੒ . ├── application │ └── usecase - usecase ├── domain │ ├── entity - domain entity(simple struct only) │ ├── repository - domain repository(interface only) │ └── service - domain service ├── infrastructure │ └── persistence │ └── rdb - implement domain repository └── interfaces └── api ├── internal │ ├── handler - http handler │ ├── http_utils - http utils │ └── middleware - http server middleware └── server.go - http server endpoint

Slide 21

Slide 21 text

DI͢Δ type UserRepository interface { GetByID(ctx context.Context, id uint64) (*User, error) } 
 type userService struct { repo UserRepository } func NewUserService(repo UserRepository) UserService { return &userService{ repo: repo, } }
 
 func (u *userService) GetByID(ctx context.Context, id uint64) (*User, error) { … }

Slide 22

Slide 22 text

ϞοΫԽͯ͠ςετ import ( "context" "testing" "github.com/golang/mock/gomock" ... ) func TestUserServiceGetByID(t *testing.T) { ... ctrl := gomock.NewController(t) defer ctrl.Finish() mockRepo := mock.NewMockUserRepository(ctrl) mockRepo.EXPECT().GetByID(c.context, c.id).Return(c.mockuser, nil) service := NewUserService(mockRepo) actual, err := GetByID(c.context, c.id) ... }

Slide 23

Slide 23 text

SQL΋ϞοΫԽ import ( "regexp"
 sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1" ) func TestGetByID(t *testing.T) { … query := `SELECT …` rows := sqlmock.NewRows(columns) rows = rows.AddRow(expextRow…) mock.ExpectQuery(query).WillReturnRows(rows)
 repo := NewUserRepository(mockDB) actual, err := repo.GetByID(c.context, c.id) … }

Slide 24

Slide 24 text

TableDrivenTests func TestSquare(t *testing.T) { cases := []struct{ expect int input int
 }{{1,1},{4,2}} for _, c := range cases { actual := Square(c.input) if actual != c.expect { t.Errorf("Square(%q) == %q, want %q",
 c. input, actual, c.expect, ) } } }

Slide 25

Slide 25 text

ͲͪΒͷํ͕ྑ͍ίʔυͰ͠ΐ͏͔ if (A || B || C) { return errors.New("something") } return nil if (A) { return errors.New("something1") } if (B) { return errors.New("something2") } if (C) { return errors.New("something3") } return nil

Slide 26

Slide 26 text

ӈΛྑ͍ͱ͍ͯ͠·͢ if (A || B || C) { return errors.New("something") } return nil if (A) { return errors.New("something1") } if (B) { return errors.New("something2") } if (C) { return errors.New("something3") } return nil

Slide 27

Slide 27 text

ϥΠϯΧόϨοδͩͱͲͷέʔε͕ςετ ͞Ε͍ͯΔ͔Θ͔Βͳ͍ ͦ΋ͦ΋Τϥʔ͸෼͚Δ΂͖

Slide 28

Slide 28 text

ϥΠϯΧόϨοδ $ go test -cover `go list ./... | grep -v mock` ok .../application/usecase coverage: 97.8% of statements ? .../domain/entity [no test files] ? .../domain/repository [no test files] ok .../domain/service coverage: 96.2% of statements ok …/infrastructure/persistence/rdb coverage: 100.0% of statements ok .../interfaces/api/internal/handler coverage: 94.7% of statements ok .../interfaces/api/internal/middleware coverage: 95.1% of statements …

Slide 29

Slide 29 text

࢒Γͷ5%ʹ͍ͭͯ cookie, err := r.Cookie("cookie_name") if err != nil { if err == http.ErrNoCookie { h.ServeHTTP(w, r) return } w.WriteHeader(http.StatusInternalServerError) return }

Slide 30

Slide 30 text

ςετΛݏ͍ͳཧ༝ w ΊΜͲ͍͘͞
 ˠΧόϨοδΛ͋͛Δୡ੒ײΛָ͍͠ͱࢥ͍͜·ͤΔɻ w ଞਓͷॻ͍ͨςετίʔυΛϝϯςφϯε͢ΔͷͭΒ͍
 ˠϞοΫԽ͢Δ͜ͱͰγϯϓϧͳςετίʔυ΁ w ࣮ߦ͢Δͷʹ͕͔͔࣌ؒΔ
 ˠίΞ਺෼ฒྻʹ࣮ߦͰ͖ΔΑ͏ʹͳͬͨɻ
 ɹʴ3%#ʹ઀ଓ͠ͳ͍෼ଟগ଎͘ͳͬͨɻ

Slide 31

Slide 31 text

(͜ͷลΓ͔Βເͷ࿩)

Slide 32

Slide 32 text

ϑϩϯτΤϯυฤ

Slide 33

Slide 33 text

ී௨ʹϢχοτςετΛ ͍ͬͺ͍ॻ͖͍ͨ

Slide 34

Slide 34 text

E2Eςετ

Slide 35

Slide 35 text

ݱঢ় w εϓϨουγʔτͰ؅ཧ͞Ε͍ͯΔςετ߲໨ॻΛ΋ͱʹखಈͰ ςετ w ͲΜͲΜػೳ͕૿͖͑ͯͯɺςετ߲໨΋૿͍͖͑ͯखಈ͕ਏ͘ ͳ͖ͬͯͨ

Slide 36

Slide 36 text

ࣗಈԽ͍ͨ͠ ?

Slide 37

Slide 37 text

Puppeteer w $ISPNF%FW5PPMT։ൃνʔϜ͕ग़ͨ͠044 w )FBEMFTT$ISPNF w $ISPNFͷΈ͔͠ಈ͔ͳ͍ w /PEF+4Ͱಈ͘ w IUUQTHJUIVCDPN(PPHMF$ISPNFQVQQFUFFS w IUUQTUSZQVQQFUFFSBQQTQPUDPN

Slide 38

Slide 38 text

Ͳ͏ͯ͠SeleniumΛ࢖Θͳ͍ͷ͔ w ಋೖ͕؆୯ w /PEF+4Ͱςετ͕ॻ͖΍͍͢ "1*͕Θ͔Γ΍͍͢ w ໨తͱͯ͠͸σάϨͷ๷ࢭ͕΄ͱΜͲͰ$ISPNF͚ͩͰ֬ೝͰ͖ Ε͹Α͍ ܦݧ্σάϨͰ*&Ͱಈ͔ͳ͘ͳͬͨέʔε͸͋·Γͳ ͍

Slide 39

Slide 39 text

ࣗಈԽ͕؆୯ʹͰ͖Δͱ͜ΖͷΈࣗಈԽ ͦͷ͏ͪશͯࣗಈԽ͍ͨ͠(ເ)͕ແཧ͸͠ͳ͍

Slide 40

Slide 40 text

੬ऑੑςετ

Slide 41

Slide 41 text

ݱঢ় w ఆظతʹ֎෦ʹ੬ऑੑςετΛ࣮ࢪ w ಺෦Ͱ΋खಈͰ࣮ࢪ

Slide 42

Slide 42 text

શͯͷϦϦʔε͝ͱʹ੬ऑੑςετ(ເ)

Slide 43

Slide 43 text

VAddy w खܰͰߴ଎ͳΫϥ΢υܕ8FC੬ऑੑݕࠪπʔϧ w ༧Ί༻ҙͨ͠63-΍ύϥϝʔλΛݩʹ੬ऑੑݕࠪΛߦ͏ w 42-ΠϯδΣΫγϣϯ944ϦϞʔτϑΝΠϧΠϯΫϧʔδϣϯ ίϚϯυΠϯδΣΫγϣϯσΟϨΫτϦτϥόʔαϧ

Slide 44

Slide 44 text

VAddy ༧Ί༻ҙͨ͠URL:
 - http://example.com/search.php?keyword1=foo&keyword2=bar 
 ΞΫηε͞ΕΔURL:
 - http://example.com/search.php?keyword1=foo&keyword2=ba - http://example.com/search.php? keyword1=foovaddy&keyword2=bar ...

Slide 45

Slide 45 text

༧Ί༻ҙ͞ΕͨURL΍ύϥϝʔλ?

Slide 46

Slide 46 text

༻ҙ͠ͳͯ͘΋͍͍ΜͰ͢

Slide 47

Slide 47 text

ςετ͢ΔURLͷऩू CI Application Proxy E2E

Slide 48

Slide 48 text

ऩूͨ͠URLΛݩʹ੬ऑੑςετ CI Application ੬ऑੑ਍அ

Slide 49

Slide 49 text

E2Eςετ͕ॻ͔Ε͍ͯΕ͹ CIͰ׬݁͞ΕΔ

Slide 50

Slide 50 text

ࣗಈͰϦϦʔε͝ͱʹ੬ऑੑ਍அͰ͖Δͷ͸ ΍͹͍ͷͰͳΔ΂͘ૣ͘΍Γ͍ͨ

Slide 51

Slide 51 text

ิࠤతͳ΋ͷͳͷͰ ࠓޙ΋֎෦ʹґཔͨ͠Γɺ ࣗ෼ͨͪͰ֬ೝͨ͠Γ͸͠·͢

Slide 52

Slide 52 text

·ͱΊ w 5FTUBCMFͳߏ੒ʹ͢΂͖ɻ w ·ͨ5FTUBCMFͳίʔυ͸ݟ΍͘͢ศར w 1VQQFUFFSͱ7"EEZΛ࢖ͬͯɺΑΓ҆৺ͳαʔϏε΁͍͖ͯ͠· ͢ɻ

Slide 53

Slide 53 text

͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ