Golang测试存储库的策略

huangapple go评论92阅读模式
英文:

Golang strategy for testing repository

问题

我有一个ClassRepository结构体,我想测试查询ClassesForLastNDays。我正在使用Gorp连接到数据库,但是我无法找到一个好的方法来测试我的查询。现在似乎我必须向数据库添加数据,但是这非常痛苦,因为我需要填充不必要的字段和外键等才能使我的测试工作。也许仓库就不应该被测试吗?

package repositories

import (
	"mobifit/app/domain/entities"
)

type ClassRepository struct {
	*Repository
}

func (c *ClassRepository) ClassesForLastNDays(days int) []entities.Class {
	classes := make([]entities.Class, 0)
	query := Select("*").
		From("Class").
		Where("VisibleAt > CURRENT_TIMESTAMP() - INTERVAL ? DAY").
		OrderBy("ClassTypeId").
		Sql()
	c.Repository.Select(classes, query, days)
	c.populateClassRelationships(classes)
	return classes
}

func (c *ClassRepository) populateClassRelationships(classes []entities.Class) {
	for i := range classes {
		class := classes[i]

		// ClassType
		c.Repository.GetById(&class.ClassType, class.ClassTypeId)

		// Instructor
		c.Repository.GetById(&class.Instructor, class.ClassType.InstructorId)

		// Equipment
		query := Select("E.*").
			From("Equipment E").
			Join("ClassEquipment CE on E.Id = CE.EquipmentId").
			Where("CE.ClassId = ?").
			Sql()
		c.Repository.Select(&class.Equipment, query, class.Id)
	}
}
英文:

I have a ClassRepository struct and I would like to test the query ClassesForLastNDays. I am using Gorp to connect to the database, but I cannot work out a nice way of testing my query. Right now it seems that I have to add data to the database, but that is pretty painful as I need to populate unnecessary fields and FKs etc to get my test to work. Perhaps repositories should just not be tested?

package repositories

import (
	"mobifit/app/domain/entities"
)

type ClassRepository struct {
	*Repository
}

func (c *ClassRepository) ClassesForLastNDays(days int) []entities.Class {
	classes := make([]entities.Class, 0)
	query := Select("*").
		From("Class").
		Where("VisibleAt > CURRENT_TIMESTAMP() - INTERVAL ? DAY").
		OrderBy("ClassTypeId").
		Sql()
	c.Repository.Select(classes, query, days)
	c.populateClassRelationships(classes)
	return classes
}

func (c *ClassRepository) populateClassRelationships(classes []entities.Class) {
	for i := range classes {
		class := classes[i]

		// ClassType
		c.Repository.GetById(&class.ClassType, class.ClassTypeId)

		// Instructor
		c.Repository.GetById(&class.Instructor, class.ClassType.InstructorId)

		// Equipment
		query := Select("E.*").
			From("Equipment E").
			Join("ClassEquipment CE on E.Id = CE.EquipmentId").
			Where("CE.ClassId = ?").
			Sql()
		c.Repository.Select(&class.Equipment, query, class.Id)
	}
}

答案1

得分: 4

编写一个集成测试来覆盖你的查询代码是非常有意义的。虽然在种子数据和访问数据库方面需要更多的时间和精力,但它可以让你对代码在生产环境中不会出错更有信心。这个安全网也将帮助你处理 GORM 或数据库升级/迁移的问题。

集成测试位于系统边界,无法进行单元测试。它们通常比单元测试运行得更慢,所以只覆盖所需的最小范围(请记住 测试金字塔)。

固定数据是一种良好的实践,可以编写可重用的数据种子。使用内存数据库可以加快测试运行速度。

英文:

Writing an integration test to cover your query code makes perfect sense. It takes more time and effort to seed and access a database but it gives you confidence that your code won't break in production. This safety net will also help you with GORM or database upgrades/migrations in the future.

Integration tests are at the system borders, where you can't do unit testing. They usually run much slower than unit tests, so cover only the required minimum. (Keep the test pyramid in mind)

Fixtures are a good practice to write reusable data seeds. An in memory database may speedup the test runs.

huangapple
  • 本文由 发表于 2014年1月22日 18:42:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/21280659.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定