ã¯ããã« TIMELINEéçºéšã®å
åã§ãã æ¬æ¥ã¯Goèšèªã®ãã¹ãã«ãããå¯èªæ§ã«ã€ããŠèããŠã¿ãŸãããã®èšäºãèªãã§ããã ããŠããçããã«ãããã¹ããæžããŠããŠä»¥äžã®ãããªåé¡ãæããçµéšãããã®ã§ã¯ãªãã§ããããã æ¢åã®ã³ãŒãã«æ©èœè¿œå ããããããã¹ãã³ãŒãã«ããã¹ãã±ãŒã¹ã远å ããããšãããããã¹ãã³ãŒããè€éã§èªã¿è§£ãã¥ããããã¹ãã远å ããã®ã«èŠåŽãã ãã¹ãã±ãŒã¹ã®çš®é¡ãå€ããå°ãããŒã¿ã远å ããã ãã§ãæ¢åã®ãã¹ããåããªããªã ãã¹ãããŒã¿ã®ç»é²æ¹æ³ãè€éã§ããã¹ãã³ãŒãã®å®è£
以åã«æéåã äžèšã®ãããªåé¡ã«å¯ŸåŠããã¹ããå®è·µçãªã·ããªãªã«åŸã£ãŠGoèšèªã®ãã¹ãã³ãŒããå®éã«æžãã€ã€éœåºŠæ¹åããŠããããšã«ããŸãã 仿§(ver.1) ãŠãŒã¶æ
å ±ã«ã¯ååãç¶æ
ïŒæå¹ãç¡å¹ïŒãšããã æå¹ãªãŠãŒã¶äžèЧãè¿åŽãã颿° LoadActive() ãå®è£
ããããã®é䞊ã³é ã¯IDã®æé ãšãã ããŒã¿æ§é ãšå®è¡SQL type User struct { ID int `db:"id"` Name string `db:"name"` State int `db:"state"` ) CREATE TABLE users ( id integer NOT NULL AUTO_INCREMENT, name varchar ( 32 ) NOT NULL , state integer NOT NULL , PRIMARY KEY (id) ); SELECT * FROM users WHERE state= 1 ORDER BY id; ãã¹ãã³ãŒãã®å®è£
(æç²) LoadActive() 颿°ã®ãã¹ãã³ãŒããšããŠã¯ä»¥äžã®ããã«ãªããŸããã ãã¹ãããŒã¿ãšããŠActive, Inactiveã®ãŠãŒã¶ãè€æ°ä»¶ç»é²ããActiveã®ãŠãŒã¶ã®ã¿ãè¿åŽãããããšã䞊ã³é ãIDã®æé ã§ããããšã確èªããŠããŸã func setupUser() { u := NewUserRepository() u.Create(model.User{Name: "user1" , State: Active}) u.Create(model.User{Name: "user2" , State: Inactive}) u.Create(model.User{Name: "user3" , State: Active}) } func teardownUser() { // ããŒã¿ã®ã¯ãªãŒã³ã¢ããåŠçãªã© } func TestUserLoadActive(t *testing.T) { t.Cleanup(teardownUser) setupUser() u := NewUserRepository() users, err := u.LoadActive() if err != nil { t.Fatalf( "expected no error but got %v" , err) } if len (users) != 2 { t.Fatalf( "expected 2 users but got %v" , len (users)) } if users[ 0 ].Name != "user1" { t.Fatalf( "expected user1 but got %v" , users[ 0 ].Name) } if users[ 1 ].Name != "user3" { t.Fatalf( "expected user3 but got %v" , users[ 1 ].Name) } } 仿§(ver.2) ver.1ã®ä»æ§ã«å¯Ÿãã以äžã®æ©èœè¿œå ãããããšã«ãªããŸããã æ°ãã«ã°ã«ãŒããšããããŒã¿æ§é ãèšãã ãŠãŒã¶ã¯1ã€ä»¥äžã®ã°ã«ãŒãã«å±ããããšãã§ãããã®ãšããïŒããªãããšãã§ããïŒ LoadActive() ãè¿åŽãããŠãŒã¶ã¯ãã°ã«ãŒãã«å±ããŠãããã®ã®ã¿ãšãã ããŒã¿æ§é ãšå®è¡SQL type User struct { ID int `db:"id"` Name string `db:"name"` State int `db:"state"` GroupID * int `db:"group_id"` ) type Group struct { ID int `db:"id"` Name string `db:"name"` ) CREATE TABLE users ( id integer NOT NULL AUTO_INCREMENT, name varchar ( 32 ) NOT NULL , state integer NOT NULL , group_id integer NULL , PRIMARY KEY (id) ); CREATE TABLE groups ( id integer NOT NULL AUTO_INCREMENT, name varchar ( 32 ) NOT NULL , PRIMARY KEY (id) ); SELECT u.* FROM users u JOIN groups g ON u. group_id =g.id WHERE u.state= 1 ORDER BY u.id; ãã¹ãã³ãŒãã®å®è£
(æç²) LoadActive() 颿°ã®ãã¹ãã³ãŒãã«ãã¹ãããŒã¿ã远å ããŠãæ°ãã«è¿œå ãããã°ã«ãŒãã®ä»æ§ã«ã€ããŠããã¹ããããããã«ããŸããã æ°ãã«ãŠãŒã¶çšã®ã¬ã³ãŒãã远å ããActiveã§ãã£ãŠãã°ã«ãŒãã«å±ããŠããªãããè¿åŽãããªãããšãã確èªãããŠããŸãã ãã®æç¹ã§ã¯ãã¹ãã³ãŒãèªäœã«ã¯æãå
¥ããããã¹ãããŒã¿ã®è¿œå ã®ã¿ãè¡ããŸãããããã§ã远å 仿§ã«å¯Ÿãã確èªèŠä»¶ã¯æºãããŠããããã§ãã func setupUser() { g := NewGroupRepository() group, _ := g.Create(model.Group{Name: "group" }) u := NewUserRepository() u.Create(model.User{Name: "user1" , State: Active, GroupID: &group.ID}) u.Create(model.User{Name: "user2" , State: Inactive, GroupID: nil }) u.Create(model.User{Name: "user3" , State: Active, GroupID: &group.ID}) u.Create(model.User{Name: "user4" , State: Active, GroupID: nil }) u.Create(model.User{Name: "user5" , State: Inactive, GroupID: &group.ID}) } func teardownUser() { // ããŒã¿ã®ã¯ãªãŒã³ã¢ããåŠçãªã© } func TestUserLoadActive(t *testing.T) { t.Cleanup(teardownUser) setupUser() u := NewUserRepository() users, err := u.LoadActive() if err != nil { t.Fatalf( "expected no error but got %v" , err) } if len (users) != 2 { t.Fatalf( "expected 2 users but got %v" , len (users)) } if users[ 0 ].Name != "user1" { t.Fatalf( "expected user1 but got %v" , users[ 0 ].Name) } if users[ 1 ].Name != "user3" { t.Fatalf( "expected user3 but got %v" , users[ 1 ].Name) } } 仿§(ver.3) ver.2ã®ä»æ§ã«å¯Ÿããããã«ä»¥äžã®æ©èœè¿œå ãããããšã«ãªããŸããã ã°ã«ãŒãã«ãç¶æ
ïŒæå¹ãç¡å¹ïŒãèšãã LoadActive() ãè¿åŽãããŠãŒã¶ã¯ãæå¹ãªã°ã«ãŒãã«å±ããŠãããã®ã®ã¿ãšãã ããŒã¿æ§é ãšå®è¡SQL CREATE TABLE users ( id integer NOT NULL AUTO_INCREMENT, name varchar ( 32 ) NOT NULL , state integer NOT NULL , group_id integer NULL , PRIMARY KEY (id) ); CREATE TABLE groups ( id integer NOT NULL AUTO_INCREMENT, name varchar ( 32 ) NOT NULL , state integer NOT NULL , PRIMARY KEY (id) ); SELECT u.* FROM users u JOIN groups g ON u. group_id =g.id WHERE u.state= 1 AND g.state= 1 ORDER BY u.id; ãã¹ãã³ãŒãã®å®è£
(æç²) ver.2 ã®å¯Ÿå¿ãšåãããã«ãã¹ãããŒã¿ã®ãã¿ãŒã³ãå¢ããããšãã§ããŸãããä»ã§ããããªãã«ã¬ã³ãŒãæ°ãããã®ã«ããã«å¢ãããšãªããšããŠãŒã¶ã®ç¶æ
ãã°ã«ãŒãæå±æç¡ãã°ã«ãŒãã®ç¶æ
ã®çµã¿åããã¶ãã¬ã³ãŒããäœããªããã°ãªãããèããã ãã§ã倧å€ããã§ãã ã ãã ããšãã¹ããæžãã®ãèŸããªã£ãŠããŸããããšããããã§ã¢ãããŒããå€ããŠã¿ãŸãã ãããã LoadActive() ãæäŸããŠããæ©èœã¯ãªãã§ããããïŒ æå®ã®æ¡ä»¶ã«åèŽããã¬ã³ãŒããè¿åŽãã ã¬ã³ãŒãã®äžŠã³é ãå®ãŸã£ããã®ã«ãã äžèšã®2ã€ã§ãããšèãããããã§ããåããããããããããäžèšããããã«ã€ããŠãã¹ããåããŠã¿ãŸãã 1çªç®ã«ã€ããŠã¯ãåã«è¿åŽãããããããªããã ãã«çç®ããã°ããã®ã§ã1ä»¶ã®ããŒã¿ã®ã¿ã察象ãšããããšã«ããŸãã ãŸããã®éããŒãã«é§åãã¹ãã®ã¢ãããŒããçšããŠãå
šçµã¿åããã®ãã¹ãããŒã¿ãçšæãããšããŠãããã¹ãã³ãŒããåé·ã«ãªããªãããã«ããŸãã // LoadActive ã®äžŠã³é ã«ã€ããŠã®ãã¹ã func TestUserLoadActive_Order(t *testing.T) { setupUser := func () { g := NewGroupRepository() group, _ := g.Create(model.Group{Name: "group" , State: Active}) u := NewUserRepository() u.Create(model.User{Name: "user1" , State: Active, GroupID: &group.ID}) u.Create(model.User{Name: "user2" , State: Active, GroupID: &group.ID}) } t.Cleanup(teardownUser) setupUser() u := NewUserRepository() users, err := u.LoadActive() if err != nil { t.Fatalf( "expected no error but got %v" , err) } if len (users) != 2 { t.Fatalf( "expected 2 users but got %v" , len (users)) } if users[ 0 ].Name != "user1" { t.Fatalf( "expected user1 but got %v" , users[ 0 ].Name) } if users[ 1 ].Name != "user2" { t.Fatalf( "expected user2 but got %v" , users[ 1 ].Name) } } // LoadActive ã®è¿åŽæ¡ä»¶ã«ã€ããŠã®ãã¹ã func TestUserLoadActive_Condition(t *testing.T) { tests := [] struct { name string userState int64 hasGroup bool groupState int64 hasUser bool }{ { "active user,active group" , Active, true , Active, true }, { "active user,inactive group" , Active, true , Inactive, false }, { "active user,no group" , Active, false , Inactive, false }, { "inactive user,active group" , Inactive, true , Active, false }, { "inactive user,inactive group" , Inactive, true , Inactive, false }, { "inactive user,no group" , Inactive, false , Inactive, false }, } setupUser := func (userState int64 , hasGroup bool , groupState int64 ) { var groupID * int64 if hasGroup { g := NewGroupRepository() group, _ := g.Create(model.Group{Name: "group" , State: groupState}) groupID = &group.ID } u := NewUserRepository() u.Create(model.User{Name: "user" , State: userState, GroupID: groupID}) } for _, tt := range tests { t.Run(tt.name, func (t *testing.T) { t.Cleanup(teardownUser) setupUser(tt.userState, tt.hasGroup, tt.groupState) u := NewUserRepository() users, err := u.LoadActive() if err != nil { t.Fatalf( "expected no error but got %v" , err) } if tt.hasUser { if len (users) != 1 { t.Fatalf( "expected 1 user but got %v" , len (users)) } } else { if len (users) != 0 { t.Fatalf( "expected 0 user but got %v" , len (users)) } } }) } } ãããªãæ¹å çŸæç¹ã§ããããªãã«èªã¿ããããã¹ãã³ãŒãã«ã¯ãªã£ããšæããŸããããŸã ãã¹ãããŒã¿ã®ç»é²åŠçã«ãããŠããã€ã課é¡ããããŸãã ãã¹ãã§ã¯æèããå¿
èŠããªããšãéNULLãªã«ã©ã (Group.Nameãªã©)ã«ã¯ãªãããå€ãæå®ããªããã°ãªããªã ããŒã¿ã®äŸåé¢ä¿ããã¹ãã³ãŒãå
ã§æèããŠãããªããã°ãªããªã äœæåŠçã®ãšã©ãŒãã³ããªã³ã°ãçç¥ããŠãããä»®ã«ç»é²ã«å€±æããŠããå Žåãã¹ãèªäœãæ£åžžã«åäœããªããªã ç°¡åã«ãã¹ãããŒã¿ãäœæããããã« factory-go ãšããã©ã€ãã©ãªãå©çšããããšã«ããŸãã ããã¯Ruby on Railsã§ããçšãããã factory_bot ãšããã©ã€ãã©ãªã«ã€ã³ã¹ãã€ã¢ããããã®ã§ãäœ¿ãæ¹ã¯äŒŒãŠããŸãã 以äžã®ãããªFactoryãçšæããŠãããŸãã usersãgroupsã«äŸåããŠãããããSubFactoryãšããæ©èœãçšããŠããŸãã var UserFactory = factory.NewFactory( &model.User{}, ).SeqInt64( "ID" , func (n int64 ) ( interface {}, error ) { return n, nil }).Attr( "Name" , func (args f.Args) ( interface {}, error ) { user := args.Instance().(*model.User) return fmt.Sprintf( "username-%d" , user.ID), nil }).Attr( "State" , func (args f.Args) ( interface {}, error ) { return Active, nil }).SubFactory( "Group" , GroupFactory).OnCreate( func (args f.Args) error { m := args.Instance().(*model.User) return insertUser(m) }) func insertUser(m *model.User) error { if m.Group != nil { m.GroupID = &m.Group.ID } _, err := // INSERT INTO usersããåŠç return err } var GroupFactory = factory.NewFactory( &model.Group{}, ).SeqInt64( "ID" , func (n int64 ) ( interface {}, error ) { return n, nil }).Attr( "Name" , func (args f.Args) ( interface {}, error ) { group := args.Instance().(*model.Group) return fmt.Sprintf( "groupname-%d" , group.ID), nil }).Attr( "State" , func (args f.Args) ( interface {}, error ) { return Active, nil }).OnCreate( func (args f.Args) error { m := args.Instance().(*model.Group) return insertGroup(m) }) func insertGroup(m *model.Group) error { _, err := // INSERT INTO groupsããåŠç return err } äžèšã®ãããªFactoryãçšæããŠããããšã§ããã¹ãã³ãŒãã®ç»é²åŠçã以äžã®ããã«ç°¡ç¥åã§ããŸãã MustCreate... ã®é¢æ°ã¯ç»é²åŠçã«å€±æãããšpanicãããããæ£ãããã¹ãããŒã¿ãæºåã§ããŠããªããŸãŸãã¹ããç¶è¡ããããšããããšã¯ãªããªã ãã¹ãã«ãããŠé¢å¿ã®ãªãã«ã©ã ã«ã€ããŠã¯æå®ããå¿
èŠããªããªãïŒæå®ããŠãããïŒ ããŒã¿ã®äŸåé¢ä¿ã«ã€ããŠãã¹ãã³ãŒãåŽã§ææ¡ããŠããå¿
èŠã¯ãªããFactoryã®äœ¿ç𿹿³ãçè§£ããŠããã°é©åãªããŒã¿çæãè¡ããã func TestUserLoadActive_Order(t *testing.T) { setupUser := func () { UserFactory.MustCreateWithOption( map [ string ] interface {}{ "Name" : "user1" }) UserFactory.MustCreateWithOption( map [ string ] interface {}{ "Name" : "user2" }) } // ... } func TestUserLoadActive_Condition(t *testing.T) { // ... setupUser := func (userState int64 , hasGroup bool , groupState int64 ) { var group *model.Group if hasGroup { group = GroupFactory.MustCreateWithOption( map [ string ] interface {}{ "State" : groupState, }).(*model.Group) } User.MustCreateWithOption( map [ string ] interface {}{ "State" : userState, "Group" : group, }) } // ... } ãŸãšã ä»åã¯Goèšèªã«ããããã¹ãã³ãŒãã®å¯èªæ§ãäžããã¢ãããŒãã«ã€ããŠãå®éã«ã³ãŒãã亀ããªããèããŠã¿ãŸããã ãã¹ãã³ãŒãã¯æåãæ
ä¿ããéèŠãªåœ¹å²ãæã£ãŠããŸããããã¹ãã³ãŒãèªäœã®ã¡ã³ããã³ã¹æ§ãäžãããšåŸã
ã«ååãªãã¹ããè¡ãããªãç¶æ
ã«é¥ãããã¡ã§ãã ãããã£ãå°æ¥ã®åé¡ãé¿ããããã«ããèªåããã¹ãã³ãŒããæžãã¿ã€ãã³ã°ã§ãä»äººãèŠãŠçè§£ããããã³ãŒãã«ãªã£ãŠããããæèããŠããã®ãéèŠãšèããŠããŸãã