Golang / GoLang System Architecture and Testing Interview Questions
How do you architect Go services for maximum testability at the package level?
Testable architecture is not an afterthought — it follows from correct dependency direction. The key principle: business logic in inner packages depends on abstractions (interfaces), not on concrete infrastructure. This enables unit testing without a database or network.
// Layered architecture with interfaces at boundaries // domain/user.go â inner layer, no infrastructure imports package domain type UserRepository interface { FindByID(ctx context.Context, id int) (*User, error) Save(ctx context.Context, u *User) error } type EmailSender interface { Send(ctx context.Context, to, subject, body string) error } type UserService struct { repo UserRepository email EmailSender } // All business logic here â easily unit testable func (s *UserService) Register(ctx context.Context, req RegisterRequest) (*User, error) { // validation, business rules â no DB/network calls directly if err := validateEmail(req.Email); err != nil { return nil, fmt.Errorf("invalid email: %w", err) } u := &User{Email: req.Email, Name: req.Name} if err := s.repo.Save(ctx, u); err != nil { return nil, fmt.Errorf("saving user: %w", err) } s.email.Send(ctx, u.Email, "Welcome!", "Thanks for joining.") return u, nil } // domain/user_test.go â fast unit test, no DB or network func TestUserService_Register(t *testing.T) { tests := []struct { name string email string repoErr error wantErr bool }{ {"valid", "alice@example.com", nil, false}, {"invalid email", "notanemail", nil, true}, {"db error", "bob@example.com", errors.New("db down"), true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { svc := &UserService{ repo: &stubRepo{saveErr: tt.repoErr}, email: &noopEmailer{}, } _, err := svc.Register(context.Background(), RegisterRequest{Email: tt.email}) if (err != nil) != tt.wantErr { t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr) } }) } }
More Related questions...