0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Goのテスト実践:NewspaperモデルのCRUDとJSONマッピングを網羅的にテストする方法

Posted at

はじめに

Goでアプリケーション開発をする際、データモデルの信頼性を確保するためのテストは欠かせません。本記事では、NewspaperモデルのCRUD操作(Create, Read, Update, Delete)とJSONマッピングのテストを網羅的に実装する方法を紹介します。testify/suiteを活用して、読みやすく再利用性の高いテストコードを作成する手順を一行ずつ解説します。

記事の目次

  1. Newspaperモデルの概要
  2. テストコード全体
  3. コード解説:一行ずつ徹底解説
  4. テストケースの実行と期待される結果

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_testmodelsパッケージのテストコード用パッケージ。プロダクションコードとは分離されます。
import (  
	"fmt"  
	"strings"  
	"testing"  
	"github.com/stretchr/testify/suite"  
	"gorm.io/gorm"  
	"go-api-newspaper/app/models"  
	"go-api-newspaper/pkg/tester"  
)  
  • fmtstrings:文字列操作やフォーマット出力に利用。
  • testify/suite:テストスイートの作成と管理を行うためのライブラリ。
  • gorm:GoのORMツール。データベース操作を簡易化します。
  • modelstester:アプリケーションのモデルとテストユーティリティをインポート。

テストスイートの定義と初期化

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. テストケースの実行と期待される結果

このテストスイートを実行すると、以下を検証できます:

  1. CRUD操作が正しく動作する。
  2. JSONマッピングが期待どおりに動作する。
  3. エラー処理が適切に行われている。

これにより、Newspaperモデルの信頼性を高めることができます。

まとめ

以上が、Newspaperモデルのテストを網羅的に実装する方法です。このテストを活用して、安心してアプリケーションを開発しましょう!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?