はじめに
Goでアプリケーション開発をする際、データモデルの信頼性を確保するためのテストは欠かせません。本記事では、Newspaper
モデルのCRUD操作(Create, Read, Update, Delete)とJSONマッピングのテストを網羅的に実装する方法を紹介します。testify/suite
を活用して、読みやすく再利用性の高いテストコードを作成する手順を一行ずつ解説します。
記事の目次
Newspaper
モデルの概要- テストコード全体
- コード解説:一行ずつ徹底解説
- テストケースの実行と期待される結果
1. Newspaper
モデルの概要
Newspaper
モデルは以下のような構造を持ち、新聞記事を管理します。
- CRUD操作:データベースを操作して記事を作成、取得、更新、削除します。
- JSONマッピング:構造体の内容をJSON形式で返す機能を備えています。
package models
import (
"encoding/json"
"go-api-newspaper/api"
)
type Newspaper struct {
ID int
Title string
ColumnName string
}
// 構造体をjsonに変換する
func (a *Newspaper) MarshalJSON() ([]byte, error) {
return json.Marshal(&api.NewspaperResponse{ // api.NewspaperResponse という別の構造体にデータを詰め替えている
Id: a.ID,
Title: a.Title,
ColumnName: a.ColumnName,
})
}
func CreateNewspaper(title string, columnName string) (*Newspaper, error) {
newspaper := &Newspaper{
Title: title,
ColumnName: columnName,
}
if err := DB.Create(newspaper).Error; err != nil {
return nil, err
}
return newspaper, nil
}
func GetNewspaper(ID int) (*Newspaper, error) {
var newspaper = Newspaper{}
if err := DB.First(&newspaper, ID).Error; err != nil {
return nil, err
}
return &newspaper, nil
}
func (a *Newspaper) Save() error {
if err := DB.Save(&a).Error; err != nil {
return err
}
return nil
}
func (a *Newspaper) Delete() error {
if err := DB.Where("id = ?", &a.ID).Delete(&a).Error; err != nil {
return err
}
return nil
}
2. テストコード全体
以下がNewspaper
モデルのテストコードです。
package models_test
import (
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/suite"
"gorm.io/gorm"
"go-api-newspaper/app/models"
"go-api-newspaper/pkg/tester"
)
type NewspaperTestSuite struct {
tester.DBSQLiteSuite
originalDB *gorm.DB
}
func TestNewspaperTestSuite(t *testing.T) {
suite.Run(t, new(NewspaperTestSuite))
}
func (suite *NewspaperTestSuite) SetupSuite() {
suite.DBSQLiteSuite.SetupSuite()
suite.originalDB = models.DB
}
func (suite *NewspaperTestSuite) AfterTest(suiteName, testName string) {
models.DB = suite.originalDB
}
func (suite *NewspaperTestSuite) TestNewspaper() {
createdNewspaper, err := models.CreateNewspaper("Test", "sports")
suite.Assert().Nil(err)
suite.Assert().Equal("Test", createdNewspaper.Title)
suite.Assert().Equal("sports", createdNewspaper.ColumnName)
getNewspaper, err := models.GetNewspaper(createdNewspaper.ID)
suite.Assert().Nil(err)
suite.Assert().Equal("Test", getNewspaper.Title)
suite.Assert().Equal("sports", getNewspaper.ColumnName)
getNewspaper.Title = "updated"
err = getNewspaper.Save()
suite.Assert().Nil(err)
updatedNewspaper, err := models.GetNewspaper(createdNewspaper.ID)
suite.Assert().Nil(err)
suite.Assert().Equal("updated", updatedNewspaper.Title)
suite.Assert().Equal("sports", updatedNewspaper.ColumnName)
err = updatedNewspaper.Delete()
suite.Assert().Nil(err)
deletedNewspaper, err := models.GetNewspaper(updatedNewspaper.ID)
suite.Assert().Nil(deletedNewspaper)
suite.Assert().True(strings.Contains("record not found", err.Error()))
}
func (suite *NewspaperTestSuite) TestNewspaperMarshal() {
newspaper := models.Newspaper{
Title: "Test",
ColumnName: "sports",
}
newspaperJSON, err := newspaper.MarshalJSON()
suite.Assert().Nil(err)
suite.Assert().JSONEq(fmt.Sprintf(`{
"columnName":"sports",
"id":0,
"title":"Test"
}`), string(newspaperJSON))
}
3. コード解説:一行ずつ徹底解説
以下で、コード全体をセクションごとに解説します。
パッケージとインポート
package models_test
-
models_test
:models
パッケージのテストコード用パッケージ。プロダクションコードとは分離されます。
import (
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/suite"
"gorm.io/gorm"
"go-api-newspaper/app/models"
"go-api-newspaper/pkg/tester"
)
-
fmt
とstrings
:文字列操作やフォーマット出力に利用。 -
testify/suite
:テストスイートの作成と管理を行うためのライブラリ。 -
gorm
:GoのORMツール。データベース操作を簡易化します。 -
models
とtester
:アプリケーションのモデルとテストユーティリティをインポート。
テストスイートの定義と初期化
type NewspaperTestSuite struct {
tester.DBSQLiteSuite
originalDB *gorm.DB
}
-
DBSQLiteSuite
:テスト用データベースをセットアップするスイート。 -
originalDB
:元のデータベース接続を保持します。
func TestNewspaperTestSuite(t *testing.T) {
suite.Run(t, new(NewspaperTestSuite))
}
-
TestNewspaperTestSuite
:テストランナー。NewspaperTestSuite
に定義されたテストケースを実行します。
Setupとクリーンアップ
func (suite *NewspaperTestSuite) SetupSuite() {
suite.DBSQLiteSuite.SetupSuite()
suite.originalDB = models.DB
}
-
SetupSuite
:全テストの前にSQLiteデータベースをセットアップ。
func (suite *NewspaperTestSuite) AfterTest(suiteName, testName string) {
models.DB = suite.originalDB
}
-
AfterTest
:各テスト後にデータベース接続を元に戻します。
CRUDテストケース
func (suite *NewspaperTestSuite) TestNewspaper() {
createdNewspaper, err := models.CreateNewspaper("Test", "sports")
suite.Assert().Nil(err)
...
}
-
CreateNewspaper
:新聞記事を作成。 -
GetNewspaper
:作成した記事を取得し、タイトルやコラム名を確認。 -
Save
:タイトルを更新し、変更が正しく反映されているか確認。 -
Delete
:記事を削除し、エラーメッセージを確認。
JSONマッピングのテストケース
func (suite *NewspaperTestSuite) TestNewspaperMarshal() {
newspaper := models.Newspaper{
Title: "Test",
ColumnName: "sports",
}
...
}
-
MarshalJSON
:構造体をJSON形式に変換し、期待されるJSONと一致するかを確認。
4. テストケースの実行と期待される結果
このテストスイートを実行すると、以下を検証できます:
- CRUD操作が正しく動作する。
- JSONマッピングが期待どおりに動作する。
- エラー処理が適切に行われている。
これにより、Newspaper
モデルの信頼性を高めることができます。
まとめ
以上が、Newspaper
モデルのテストを網羅的に実装する方法です。このテストを活用して、安心してアプリケーションを開発しましょう!