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

时间:2014-10-27 02:51:14

标签: testing model-view-controller go

所以我想在测试中将控制器与模型隔离开来,以便在出现问题时能够轻松找出问题。之前,我只是使用模拟数据点击端点,但很难进行故障排除,因为测试从路由器一直运行到数据存储区。所以我想我可能只为每个控制器(和模型)创建两个版本(MockController vs 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查询,只验证有效负载并返回有效的响应。

您如何看待这种设计?你有更好的实施方式吗?

2 个答案:

答案 0 :(得分:0)

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

实时:

u:= NewUserController() s:= NewServer(u)

在测试中:

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

答案 1 :(得分:0)

我会尝试在模型和控制器包中使用更细的变体,如下所示:

// 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{}}
}

对于控制器测试,请考虑ResponseRecorder of httptest package