So this one is really weird, I'm trying to get a mock response that renders JSON. My test looks like this:
import (
"fmt"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
)
...
func TestMessageFromResponse(t *testing.T) {
mc := MyController{}
body := "{ \"message\":\"kthxbai\" }"
w := httptest.NewRecorder()
w.Write([]byte(body))
resp := w.Result()
msg := mc.messageFromResponse(resp)
if msg != "kthxbai" {
t.Errorf("Expected response body to be kthxbai but was %s", msg)
}
}
I'm testing the method messageFromResponse on MyControllerbut its not even building. When I run go test in my project directory, I get the following error:
./my_controller_test.go:115: w.Result undefined (type *httptest.ResponseRecorder has no field or method Result)
I should also mention that I am successfully using httptest.ResponseRecorder as a writer stub elsewhere in this same file, but it's just failing when I try to access Result().
I initially addressed this as a comment because I was unsure of relevance, but for posterity:
The online godoc always references the latest release. In this case, the Result() method was added in Go1.7 which only released last week. When in doubt, check your local godoc by running godoc -server or godoc <packagename>.
Related
My application uses other external library (which uses zap library) to print audit-logs and now I want to test the printed audit-logs in my golang testing file.
Can someone help me with it.
You could take a look at the zaptest package:
Package zaptest provides a variety of helpers for testing log output.
As example, in your test:
func Test_zap(t *testing.T) {
t.Run("Handle log message", func(t *testing.T) {
// Given
observedZapCore, observedLogs := observer.New(zap.InfoLevel)
observedLogger := zap.New(observedZapCore)
// When
myFunction(observedLogger)
// Then
require.Equal(t, 1, observedLogs.Len())
firstLog := observedLogs.All()[0]
assert.Equal(t, "log myFunction", firstLog.Message)
})
}
where myfunction is
func myFunction(logger *zap.Logger) {
logger.Info("log myFunction")
}
Check also this interesting article about that
I have a Go API built using the Gin framework.
Reading the docs in the testing section here, i tried to implement something similar:
main.go
package main
import (
"mes/routes"
"github.com/gin-gonic/gin"
)
func setupMainRoutes(engine *gin.Engine) {
engine.GET("/mesg/:language/services", routes.AllServices)
engine.GET("/mesg/:language/service/:id", routes.OneService)
engine.GET("/mesg/:language/services/search", routes.SearchService)
}
func setupErrorRoutes(engine *gin.Engine) {
engine.NoRoute(routes.Error404Handler)
}
func setupServer() *gin.Engine {
// Gin Mode
gin.SetMode(gin.ReleaseMode)
// Creates the Gin Engine
engine := gin.New()
// Setup the API Routes
setupMainRoutes(engine)
// Setup Error Routes
setupErrorRoutes(engine)
// Return engine
return engine
}
func main() {
// Run the engine
setupServer().Run()
}
main_test.go
package main
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
/************** Error Handling Tests **************/
func TestPing404Errors1Of3(t *testing.T) {
router := setupServer()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 404, w.Code)
}
However, it seems that I cannot move the main_test.go to another folder because the setupServer() function becomes undefined.
Is there a way to classify all my tests in a sub folder ?
Moving main_test.go to another folder means that you will be testing/calling setupServer() from a different package. For that, you would need to export as SetupServer() and import the package which contain SetupServer() in your test file. Unfortunately you can't do that with your current file structure because we can't import package main. Therefore, you need to rename the package if you really want to do so.
Having said that, putting the test files _test.go in the same directory (hence same package) is a common practice in Go.
I have following code
func (s *MyRepo) InsertOrder(ctx context.Context, orderID string) error {
query := `INSERT INTO orders (orderID) VALUES (?)`
stmt, err := s.db.RawDatabase().PrepareContext(ctx, query)
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, orderID)
if err != nil {
//log err
}
return err
}
And the corresponding test case is
func TestMyRepo_InsertOrder_Success(t *testing.T) {
orderID := "orderID"
mockDB, repo := getDBStore()
query := `[INSERT INTO orders (orderID) VALUES (?)]`
mockDB.ExpectPrepare(query).
ExpectExec().
WithArgs(orderID).
WillReturnResult(sqlmock.NewResult(1, 1)).
WillReturnError(nil)
err := repo.InsertOrder(context.Background(), orderID)
assert.Nil(t, err)
}
But this doesn't test if defer stmt.Close() has been called or not (which gets called once the function ends). How can I test this?
It looks like you are making use of data-dog's sqlmock package, so you ought to be able to use ExpectClose() to register the expectation that the database will be closed, and ExpectationsWereMet() to collect this information.
If you're using some other package, feel free to link it; there's probably something similar available, and worst-case you can write your own wrapper around their wrapper. Making sure that a particular method of a particular dependency was called is a fairly common desire when developers write tests using mocks, so most of the better mock packages will go out of their way to provide some sort of API to check that.
As noted in the comments on this question, tests of this nature are often of somewhat questionable value and can seem like they exist more to increase a dubious metric like % code coverage than to increase code reliability or maintainability.
I am still new in Golang. Do you have any ideas on how to create a multiple httptest.NewRequest efficiently in your Go test file? Usually I initiate a new variable two create new request.
For instance :
r1 := httptest.NewRequest("GET", url, nil)
r1.Header.Add("Accept-Language", "id")
r1.AddCookie(&cookie)
r2 := httptest.NewRequest("GET", url, nil)
r1.Header.Add("Accept-Language", "id")
So I want to create 2 different request, in fact I have to initiate 2 variable in order to generate new request. I also uses test table so I can't add the cookie after the first test is running.
There is little reason to optimize tests for performance, as tests don't get compiled into your app and they don't run with your app; just don't do "senseless" slow things. They run "offline" to verify the correctness of your app, so performance of tests is nowhere near critical.
So write your tests to be clean and short in source code.
But that being said, you can create a utility function to create and set up similar requests, for example:
func newRequest(url string) *http.Request {
r := httptest.NewRequest("GET", url, nil)
r.Header.Add("Accept-Language", "id")
return r
}
And using it to reconstruct your example:
r1 := newRequest(url)
r1.AddCookie(&cookie)
r2 := newRequest(url)
I did used Multiple httptest.NewRequest with different condition in Go Test
the key is to reinitialize - this worked for me to test multiple scenario
rr = httptest.NewRecorder()
for example
t.Run("should continue to next handler when scope are valid and permission are not valid", func(t *testing.T) {
isFunctionInvoked = false
rr := httptest.NewRecorder()
// creates a test context and gin engine
_, r := gin.CreateTestContext(rr)
r.Use(func(c *gin.Context) {
c.Set(AUTH_RESPONSE, ir)
})
r.GET("/me", HasPermissionsOrHasScope(&[]string{"invalidPermission"}, "validScope"), func(context *gin.Context) {
isFunctionInvoked = true
return
})
r.GET("/me/test2", HasPermissionsOrHasScope(&[]string{"invalidPermission"}, "validScope2"), func(context *gin.Context) {
isFunctionInvoked = true
return
})
request, _ := http.NewRequest(http.MethodGet, "/me", http.NoBody)
rr = httptest.NewRecorder()
isFunctionInvoked = false
r.ServeHTTP(rr, request)
assert.Equal(t, true, isFunctionInvoked)
assert.Equal(t, http.StatusOK, rr.Code)
request2, _ := http.NewRequest(http.MethodGet, "/me/test2", http.NoBody)
isFunctionInvoked = false
rr = httptest.NewRecorder()
r.ServeHTTP(rr, request2)
assert.Equal(t, http.StatusOK, rr.Code)
})
There might be better way using Test Table.
The problem i faced is, during assertion if i make scopes invalid it was giving 200 because rr := httptest.NewRecorder() rr used old response, to overcome that i need to reset rr everytime
I am currently trying to test a piece of my code that runs a query on the datastore before putting in a new entity to ensure that duplicates are not created. The code I wrote works fine in the context of the app, but the tests I wrote for that methods are failing. It seems that I cannot access data put into the datastore through queries in the context of the testing package.
One possibility might lie in the output from goapp test which reads: Applying all pending transactions and saving the datastore. This line prints out after both the get and put methods are called (I verified this with log statements).
I tried closing the context and creating a new one for the different operations, but unfortunately that didn't help either. Below is a simple test case that Puts in an object and then runs a query on it. Any help would be appreciated.
type Entity struct {
Value string
}
func TestEntityQuery(t *testing.T) {
c, err := aetest.NewContext(nil)
if err != nil {
t.Fatal(err)
}
defer c.Close()
key := datastore.NewIncompleteKey(c, "Entity", nil)
key, err = datastore.Put(c, key, &Entity{Value: "test"})
if err != nil {
t.Fatal(err)
}
q := datastore.NewQuery("Entity").Filter("Value =", "test")
var entities []Entity
keys, err := q.GetAll(c, &entities)
if err != nil {
t.Fatal(err)
}
if len(keys) == 0 {
t.Error("No keys found in query")
}
if len(entities) == 0 {
t.Error("No entities found in query")
}
}
There is nothing wrong with your test code. The issue lies in the Datastore itself. Most queries in the HR Datastore are not "immediately consistent" but eventually consistent. You can read more about this in the Datastore documentation.
So basically what happens is that you put an entity into the Datastore, and the SDK's Datastore "simulates" the latency that you can observe in production, so if you run a query right after that (which is not an ancestor query), the query result will not include the new entity you just saved.
If you put a few seconds sleep between the datastore.Put() and q.GetAll(), you will see the test passes. Try it. In my test it was enough to sleep just 100ms, and the test always passed. But when writing tests for such cases, use the StronglyConsistentDatastore: true option as can be seen in JonhGB's answer.
You would also see the test pass without sleep if you'd use Ancestor queries because they are strongly consistent.
The way to do this is to force the datastore to be strongly consistent by setting up the context like this:
c, err := aetest.NewContext(&aetest.Options{StronglyConsistentDatastore: true})
if err != nil {
t.Fatal(err)
}
Now the datastore won't need any sleep to work, which is faster, and better practice in general.
Update: This only works with the old aetest package which was imported via appengine/aetest. It does not work with the newer aetest package which is imported with google.golang.org/appengine/aetest. App Engine has changed from using an appengine.Context to using a context.Context, and consequently the way that the test package now works is quite different.
To compliment #JohnGB's answer in the latest version of aetest, there are more steps to get a context with strong consistency. First create an instance, then create a request from that instance, which you can use to produce a context.
inst, err := aetest.NewInstance(
&aetest.Options{StronglyConsistentDatastore: true})
if err != nil {
t.Fatal(err)
}
defer inst.Close()
req, err := inst.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err)
}
ctx := appengine.NewContext(req)