如何在测试中将模型与控制器分离



所以我想在测试中将控制器与模型隔离开来,这样在出现问题时我就可以轻松地找出问题所在。以前,我只是用模拟数据访问端点,但很难进行故障排除,因为测试从路由器一直运行到数据存储。所以我想,也许我会为每个控制器(和模型)创建两个版本(MockController和Controller),并根据模式变量的值使用一个。简而言之,这就是我计划如何实现它

const mode string = "test"
// UserModelInterface is the Interface for UserModel
type UserModelInterface interface {
    Get() 
}
// UserControllerInterface is the Interface for UserController
type UserControllerInterface interface {
    Login()
}
// NewUserModel returns a new instance of user model
func NewUserModel() UserModelInterface {
    if mode == "test" {
        return &MockUserModel{}
    } else {
        return &UserModel{}
    }
}
// NewUserController returns a new instance of user controller
func NewUserController(um UserModelInterface) UserControllerInterface {
    if mode == "test" {
        return &MockUserController{}
    } else {
        return &UserController{}
    }
}
type (
    UserController struct {um UserModelInterface}
    UserModel struct {}
    // Mocks
    MockUserController struct {um UserModelInterface}
    MockUserModel struct {}
)
func (uc *UserController) Login() {}
func (um *UserModel) Get() {}
func (uc *MockUserController) Login() {}
func (um *MockUserModel) Get() {}
func main() {
    um := NewUserModel()
    uc := NewUserController(um)
}

这样,我就可以跳过MockUserController.Login()中的sql查询,只验证有效负载并返回有效响应。

你觉得这个设计怎么样?你有更好的实现吗?

我会让调用NewUserController()和NewUserModel()的代码来决定是创建mock实现还是实际实现。如果您一直使用依赖项注入模式直到顶部,您的代码将变得更清晰,耦合性也会降低。例如,如果用户控制器被服务器使用,它看起来就像

真实:

u:=新建用户控制器()s:=新服务器(u)

测试中:

u:=NewMockUserController()s:=NewServer(u)

我会在模型和控制器包上尝试一个更纤薄的变体,比如:

// inside package controllers
type UserModel interface {
    Get() // the methods you need from the user model
}
type User struct {
    UserModel
}
// inside package models
type User struct {
    // here the User Model
}

// inside package main
import ".....controllers"
import ".....models"
func main() {
    c := &controllers.User{&models.User{}}
}
// inside main_test.go
import ".....controllers"
type MockUser struct {
}

func TestX(t *testing.T) {
    c := &controllers.User{&MockUser{}}
}

对于控制器测试,请考虑httptest包的ResponseRecorder

最新更新