Golang / GoLang Interfaces and Object Oriented Interview Questions
How do you combine table-driven tests with interface mocks in Go?
The two most important Go testing patterns together: table-driven tests for coverage and interface mocks for isolation. Combining them gives thorough, readable, and maintainable tests for any component that has external dependencies.
// System under test type UserEmailer interface { GetEmail(userID int) (string, error) } type Mailer interface { Send(to, subject, body string) error } type NotificationService struct { emailer UserEmailer mailer Mailer } func (ns *NotificationService) Notify(userID int, msg string) error { email, err := ns.emailer.GetEmail(userID) if err != nil { return fmt.Errorf("get email: %w", err) } return ns.mailer.Send(email, "Notification", msg) } // Test mocks type fakeEmailer struct{ email string; err error } func (f *fakeEmailer) GetEmail(int) (string, error) { return f.email, f.err } type fakeMailer struct{ sent []string; err error } func (m *fakeMailer) Send(to, _, _ string) error { m.sent = append(m.sent, to) return m.err } // Table-driven test combining both mocks func TestNotify(t *testing.T) { tests := []struct { name string emailErr error mailerErr error wantErr bool wantSent int }{ {"happy path", nil, nil, false, 1}, {"email lookup fails", errors.New("db error"), nil, true, 0}, {"mailer fails", nil, errors.New("smtp error"), true, 0}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { mailer := &fakeMailer{err: tc.mailerErr} svc := &NotificationService{ emailer: &fakeEmailer{email: "u@x.com", err: tc.emailErr}, mailer: mailer, } err := svc.Notify(1, "hello") if (err != nil) != tc.wantErr { t.Errorf("want err=%v, got %v", tc.wantErr, err) } if len(mailer.sent) != tc.wantSent { t.Errorf("want %d sent, got %d", tc.wantSent, len(mailer.sent)) } }) } }
More Related questions...