├── .gitignore
├── LICENSE
├── README.md
├── go-redis
└── suite.go
├── go.mod
├── go.sum
├── mysql
├── migration.go
└── mysql_suite.go
└── testada.go
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | /.idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Golangid
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # testada
2 | This package is just a boilerplate for doing integration testing in Golang. We already separate a few code that may same when doing integration testing in every test-case.
3 |
4 | ## Index
5 |
6 | * [Support](#support)
7 | * [How To Use](#how-to-use)
8 | * [Contribution](#contribution)
9 |
10 |
11 | # Support
12 |
13 | You can file an [Issue](https://github.com/golangid/testada/issues/new).
14 | See documentation in [Godoc](https://godoc.org/github.com/golangid/testada)
15 |
16 | # How To Use
17 |
18 | ### Prerequisite Library and Tools
19 | - A live DB on your project, you could use docker to spawn a live DB/services
20 | - `github.com/stretchr/testify`. A testing package, really usefull. And all of this package use this package. Make sure understand how to use it, before using our boilerplate test-suite.
21 | - DB drivers, depend on what driver you use.
22 |
23 | #### List DB driver and libraries that already supported here
24 | |services| driver and libraries |testada-package|
25 | |--------|--------|---------------|
26 | | Mysql |
- github.com/go-sql-driver/mysql
- sql/db
| github.com/golangid/testada/mysql|
27 | | Redis | github.com/go-redis/redis | github.com/golangid/testada/go-redis |
28 |
29 | ## Usage In MYSQL
30 | Complete file can be seen in: [example-testada-mysql](https://github.com/golangid/testada-example/blob/master/mysql/repository_test.go)
31 |
32 | ```go
33 | import (
34 | // ... other imports
35 | "github.com/stretchr/testify/suite"
36 | "github.com/golangid/testada/mysql"
37 | )
38 |
39 | type mysqlCategorySuiteTest struct {
40 | mysql.MysqlSuite
41 | }
42 |
43 | func TestCategorySuite(t *testing.T) {
44 | if testing.Short() {
45 | t.Skip("Skip category mysql repository test")
46 | }
47 | dsn := os.Getenv("MYSQL_TEST_URL")
48 | if dsn == "" {
49 | dsn = "root:root-pass@tcp(localhost:33060)/testing?parseTime=1&loc=Asia%2FJakarta&charset=utf8mb4&collation=utf8mb4_unicode_ci"
50 | }
51 | categorySuite := &mysqlCategorySuiteTest{
52 | mysql.MysqlSuite{
53 | DSN: dsn,
54 | MigrationLocationFolder: "migrations",
55 | },
56 | }
57 |
58 | suite.Run(t, categorySuite)
59 | }
60 |
61 | func (s *mysqlCategorySuiteTest) SetupTest() {
62 | log.Println("Starting a Test. Migrating the Database")
63 | err, _ := s.Migration.Up()
64 | require.NoError(s.T(), err)
65 | log.Println("Database Migrated Successfully")
66 | }
67 |
68 | func (s *mysqlCategorySuiteTest) TearDownTest() {
69 | log.Println("Finishing Test. Dropping The Database")
70 | err, _ := s.Migration.Down()
71 | require.NoError(s.T(), err)
72 | log.Println("Database Dropped Successfully")
73 | }
74 |
75 | func (m *mysqlCategorySuiteTest) TestStore() {
76 | // Your test code will be placed here
77 | // This function will do the integration-test for Store function.
78 | // Your Store function will test directly with a real DB by this TestFunction
79 | }
80 | func (m *mysqlCategorySuiteTest) TestOtherFunction() {
81 | // Your test code will be placed here
82 | // This function will do the integration-test for your defined function as you want.
83 | // Your Store function will test directly with a real DB by this TestFunction
84 | }
85 | // ... Add more test according to your cases
86 |
87 | ```
88 | ## Usage In Redis with GO-REDIS package
89 | This example use this driver: `github.com/go-redis/redis`
90 | Complete file can be seen in: [example-testada-redis](https://github.com/golangid/testada-example/blob/master/redis/cache_test.go)
91 |
92 | ```go
93 | import(
94 | // ... other imports
95 | "github.com/stretchr/testify/suite"
96 | goRedisSuite "github.com/golangid/testada/go-redis"
97 | )
98 | type redisHandlerSuite struct {
99 | goRedisSuite.RedisSuite
100 | }
101 |
102 | func TestRedisSuite(t *testing.T) {
103 | if testing.Short() {
104 | t.Skip("Skip test for redis repository")
105 | }
106 | redisHostTest := os.Getenv("REDIS_TEST_URL")
107 | if redisHostTest == "" {
108 | redisHostTest = "localhost:6379"
109 | }
110 | redisHandlerSuiteTest := &redisHandlerSuite{
111 | goRedisSuite.RedisSuite{
112 | Host: redisHostTest,
113 | },
114 | }
115 | suite.Run(t, redisHandlerSuiteTest)
116 | }
117 |
118 | func getItemByKey(client *redis.Client, key string) ([]byte, error) {
119 | return client.Get(key).Bytes()
120 | }
121 | func seedItem(client *redis.Client, key string, value interface{}) error {
122 | jybt, err := json.Marshal(value)
123 | if err != nil {
124 | return err
125 | }
126 | return client.Set(key, jybt, time.Second*30).Err()
127 | }
128 | func (r *redisHandlerSuite) TestSet() {
129 | // Your test code will be placed here
130 | // This function will do the integration-test for your defined function as you want.
131 | // Your Store function will test directly with a real DB by this TestFunction
132 | }
133 | func (r *redisHandlerSuite) TestGet() {
134 | // Your test code will be placed here
135 | // This function will do the integration-test for your defined function as you want.
136 | // Your Store function will test directly with a real DB by this TestFunction
137 | }
138 | // ... Add more test according to your cases
139 | ```
140 |
141 | # Contribution
142 | We accept any contributions including PR, or just an issue.
143 |
--------------------------------------------------------------------------------
/go-redis/suite.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "github.com/go-redis/redis"
5 | "github.com/stretchr/testify/suite"
6 | )
7 |
8 | type RedisSuite struct {
9 | suite.Suite
10 | Host string
11 | Password string
12 | DB int
13 | Client *redis.Client
14 | }
15 |
16 | func (r *RedisSuite) SetupSuite() {
17 | r.Client = redis.NewClient(&redis.Options{
18 | Addr: r.Host,
19 | Password: r.Password,
20 | DB: r.DB,
21 | })
22 | }
23 |
24 | func (r *RedisSuite) TearDownSuite() {
25 | r.Client.Close()
26 | }
27 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/golangid/testada
2 |
3 | require (
4 | github.com/Microsoft/go-winio v0.4.11 // indirect
5 | github.com/docker/distribution v2.7.0+incompatible // indirect
6 | github.com/docker/docker v1.13.1 // indirect
7 | github.com/docker/go-connections v0.4.0 // indirect
8 | github.com/docker/go-units v0.3.3 // indirect
9 | github.com/go-redis/redis v6.15.1+incompatible
10 | github.com/go-sql-driver/mysql v1.4.1
11 | github.com/golang-migrate/migrate v3.5.4+incompatible
12 | github.com/onsi/ginkgo v1.7.0 // indirect
13 | github.com/onsi/gomega v1.4.3 // indirect
14 | github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
15 | github.com/pkg/errors v0.8.1 // indirect
16 | github.com/stretchr/testify v1.3.0
17 | google.golang.org/appengine v1.4.0 // indirect
18 | )
19 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
2 | github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
3 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtfRN0TFIwt6YFL7N9RU=
6 | github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
7 | github.com/docker/docker v1.13.1 h1:5VBhsO6ckUxB0A8CE5LlUJdXzik9cbEbBTQ/ggeml7M=
8 | github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
9 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
10 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
11 | github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
12 | github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
13 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
14 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
15 | github.com/go-redis/redis v6.15.1+incompatible h1:BZ9s4/vHrIqwOb0OPtTQ5uABxETJ3NRuUNoSUurnkew=
16 | github.com/go-redis/redis v6.15.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
17 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
18 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
19 | github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA=
20 | github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk=
21 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
22 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
23 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
24 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
25 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
26 | github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
27 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
28 | github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
29 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
30 | github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
31 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
32 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
33 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
34 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
35 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
36 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
37 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
38 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
39 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
40 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
41 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
42 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
43 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
44 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
45 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
46 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
47 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
48 | google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
49 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
50 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
51 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
52 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
53 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
54 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
55 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
56 | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
57 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
58 |
--------------------------------------------------------------------------------
/mysql/migration.go:
--------------------------------------------------------------------------------
1 | package mysql
2 |
3 | import (
4 | "database/sql"
5 | "strings"
6 |
7 | "github.com/golang-migrate/migrate"
8 | _mysql "github.com/golang-migrate/migrate/database/mysql"
9 | )
10 |
11 | type migration struct {
12 | Migrate *migrate.Migrate
13 | }
14 |
15 | func (this *migration) Up() (error, bool) {
16 | err := this.Migrate.Up()
17 | if err != nil {
18 | if err == migrate.ErrNoChange {
19 | return nil, true
20 | }
21 | return err, false
22 | }
23 | return nil, true
24 | }
25 |
26 | func (this *migration) Down() (error, bool) {
27 | err := this.Migrate.Down()
28 | if err != nil {
29 | return err, false
30 | }
31 | return nil, true
32 | }
33 |
34 | func runMigration(dbConn *sql.DB, migrationsFolderLocation string) (*migration, error) {
35 | dataPath := []string{}
36 | dataPath = append(dataPath, "file://")
37 | dataPath = append(dataPath, migrationsFolderLocation)
38 |
39 | pathToMigrate := strings.Join(dataPath, "")
40 |
41 | driver, err := _mysql.WithInstance(dbConn, &_mysql.Config{})
42 | if err != nil {
43 | return nil, err
44 | }
45 |
46 | m, err := migrate.NewWithDatabaseInstance(pathToMigrate, mysql, driver)
47 | if err != nil {
48 | return nil, err
49 | }
50 | return &migration{Migrate: m}, nil
51 | }
52 |
--------------------------------------------------------------------------------
/mysql/mysql_suite.go:
--------------------------------------------------------------------------------
1 | package mysql
2 |
3 | import (
4 | "database/sql"
5 |
6 | driverSql "github.com/go-sql-driver/mysql"
7 | _ "github.com/golang-migrate/migrate/source/file"
8 | "github.com/stretchr/testify/require"
9 | "github.com/stretchr/testify/suite"
10 | )
11 |
12 | const mysql = "mysql"
13 |
14 | // MysqlSuite struct for MySQL Suite
15 | type MysqlSuite struct {
16 | suite.Suite
17 | DSN string
18 | DBConn *sql.DB
19 | Migration *migration
20 | MigrationLocationFolder string
21 | DBName string
22 | }
23 |
24 | // SetupSuite setup at the beginning of test
25 | func (s *MysqlSuite) SetupSuite() {
26 | DisableLogging()
27 |
28 | var err error
29 |
30 | s.DBConn, err = sql.Open(mysql, s.DSN)
31 | err = s.DBConn.Ping()
32 | require.NoError(s.T(), err)
33 | _, err = s.DBConn.Exec("set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';")
34 | require.NoError(s.T(), err)
35 | _, err = s.DBConn.Exec("set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';")
36 | require.NoError(s.T(), err)
37 |
38 | s.Migration, err = runMigration(s.DBConn, s.MigrationLocationFolder)
39 | require.NoError(s.T(), err)
40 | }
41 |
42 | // TearDownSuite teardown at the end of test
43 | func (s *MysqlSuite) TearDownSuite() {
44 | s.DBConn.Close()
45 | }
46 |
47 | func DisableLogging() {
48 | nopLogger := NopLogger{}
49 | driverSql.SetLogger(nopLogger)
50 | }
51 |
52 | type NopLogger struct {
53 | }
54 |
55 | func (l NopLogger) Print(v ...interface{}) {}
56 |
--------------------------------------------------------------------------------
/testada.go:
--------------------------------------------------------------------------------
1 | package testada
2 |
3 | /*
4 | Testada is a package to initate testing suite.
5 | Currently support mysql database testing.
6 | */
7 |
--------------------------------------------------------------------------------