I'm trying to test the following method:
//AuthenticationMiddleware Middleware which handles all of the authentication.
func AuthenticationMiddleware(context context.ContextIntf, w web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
//Check if url is one that doesn't need authorization. If not than send them to the login page.
for _, url := range AuthMWInstance.GetInfo().nonAuthURLs {
if url.Method == r.Method && strings.Contains(r.URL.Path, url.DomainName) {
next(w, r)
return
}
}
if errSt := CheckForAuthorization(context, r, w); errSt != nil {
responses.Write(w, responses.Unauthorized(*errSt))
return
}
defer context.GetInfo().Session.SessionRelease(w)
next(w, r)
}
In this case, there's a SessionRelease
that gets invoked iff r
contains a URL that requires authorization, and that authorization was successful.
It may be important to know that :
type MiddlewareSt struct {
//NonAuthUrls URLs that can be accessed without a token.
nonAuthURLs []url.URLSt
}
type MiddlewareIntf interface {
GetInfo() *MiddlewareSt
CheckTokenAndSetSession(context context.ContextIntf, r *web.Request, w web.ResponseWriter,
token string, scope string, remoteAddr string) *errors.ErrorSt
}
var AuthMWInstance MiddlewareIntf
and that CheckForAuthorization
's return value ultimately relies upon AuthMWInstance
My Test Strategy
- Create a stub middleware instance to initialize
AuthMWInstance
to, that simply returnsnil
forCheckTokenAndSetSession
(with the session setting abstracted out, of course, to the creation of the stub object itself, which has theSession
), and aMiddlewareSt
full of fakenonAuthURLs
forGetInfo()
- Create a mock
session.Store
that, for all tests except the Sanity Test, expects zero calls toSessionRelease
.
It's probably worth noting (but assumed) that I'm using testify,mockery libraries for the mocking and the assertion stuff.
The test
Is implemented thus:
func TestAuthenticationMiddleware(t *testing.T) {
// bring in the errors
sdkTesting.InitErrors()
// create/set up the test doubles
// mock session
sessionMock := new(testing_mock.MockStore)
// temporarily set AuthMWInstance to a stub
instance := AuthMWInstance
AuthMWInstance = &StubMiddlewareInstance{
Session: sessionMock,
}
// AuthMWInstance.Session
defer func() { AuthMWInstance = instance }()
// fake ResponseWriter
w := new(StubResponseWriter)
// fake web requests
requestWithoutAuth := new(web.Request)
requestWithoutAuth.Request = httptest.NewRequest("GET",
"http://example.com/logout",
nil,
)
// do tests here
t.Run("AuthorizationNotRequired", func(t *testing.T) {
// place expectations on sessionMock, namely that it does
// **not** invoke `SessionRelease`
sessionMock.On("SessionRelease", w).
Times(0)
AuthenticationMiddleware(new(context.Context),
w,
requestWithoutAuth,
web.NextMiddlewareFunc(func(web.ResponseWriter, *web.Request) {}))
sessionMock.AssertExpectations(t)
})
}
Runtime behavior
The following false fail happens: . It's literally as if, instead of doing:
sessionMock.On("SessionRelease", w).
Times(0)
, I was like:
sessionMock.On("SessionRelease", w).
Once()
NOTE session.Store.SessionRelease
does not return anything, hence why I didn't even bother using Return()
.
Am I asserting that it is to be called exactly zero times right?
I feel a bit silly for this.
The problem was that I was bothering with
when I could have simply said
(Documentation on that method here)
Doing the latter resolved the issue, and did exactly what I was trying to accomplish.