I'm studying the outyet example project from https://github.com/golang/example/tree/master/outyet. The test file does not cover the case where http.Head(url) returns an error. I would like to extend the unit tests to cover the if statement where the error is logged (https://github.com/golang/example/blob/master/outyet/main.go#L100). I would like to mock http.Head(), but I'm not sure how to do this. How can this be done?
The http.Head function simply calls the Head method on the default HTTP client (exposed as http.DefaultClient). By replacing the default client within your test, you can change the behaviour of these standard library functions.
In particular, you will want a client that sets a custom transport (any object implementing the http.RoundTripper interface). Something like the following:
type testTransport struct{}
func (t testTransport) RoundTrip(request *http.Request) (*http.Response, error) {
# Check expectations on request, and return an appropriate response
}
...
savedClient := http.DefaultClient
http.DefaultClient = &http.Client{
Transport: testTransport{},
}
# perform tests that call http.Head, http.Get, etc
http.DefaultClient = savedClient
You could also use this technique to mock network errors by returning an error from your transport rather than an HTTP response.
Related
I have a #Service which uses a WebClient to return a Mono<Something>. I want to test that the service adds the right data to the request - headers, URI, body. My test's approach is to inject a mocked WebClient.Builder into the service, and provide a WebClient with a custom exchange function:
#BeforeEach
void preProgramWebClientBuilder() {
webClient = WebClient.builder()
.baseUrl(TEST_REMOTE_BASE_URL)
.exchangeFunction(clientRequest -> {
// ...
}).build();
// webClientBuilder is the mockito-managed mock
when(webClientBuilder.baseUrl(anyString())).thenReturn(webClientBuilder);
when(webClientBuilder.build()).thenReturn(webClient);
}
This works well, for checking request host/path/query parameters/headers, with the exchange function either performing the checks itself, or setting the clientRequest aside for the test to do the checks. But I have not found a way to extract the body from the clientRequest object, to perform assertions on it.
Fully mocking the WebClient yields some ugly test initialization code, which I'd like to avoid. Is there a decent way to extract the request body from the clientRequest?
Just to mention it: I don't see how I can use a StepVerifier here. StepVerifier expects to get the Publisher to verify - and getting the body of the request as a publisher is exactly what I haven't managed to do. A WebTestClient has the same problem - I can perform a request with it, then do assertions on the response, but I can't substitute it for the regular WebClient in the service in order to perform assertions on the request emitted by the service.
I have an application that defines a type Client struct {} which talks to various other clients in my code that talk to services like github, elasticsearch etc.
Now I have the following ES code in one of my packages
type SinkService interface {
Write(context, index, mapping, doc)
}
type ESSink struct {
client *elastic.Client
}
func NewESSink() *ESSink {}
// checks if the index exists and writes the doc
func (s *ESSink) Write(context, index, mapping, doc) {}
I use this method in my main client that runs the whole application like this c.es.Write(...). Now if I want to write client_test.go I can simply make a mockESSink and use it with some stub code but that won't cover the lines written in my ES code.
How do I unit test my ES code? My ESSink uses an elastic.Client. How do I mock that?
I would like to embed some mock ES client that gives me stub responses and I will be able to test my ESSink.Write method that way.
Based on your question, I assume you're using github.com/olivere/elastic, and you want to be able to test by using stub http responses. When I first read this question, I also have never written Go test code that use ES client. So, in addition to answering this question, I'm also sharing how I find out the answer from the godocs.
First, we can see that elastic.NewClient accepts client option functions. So I checked what kind of client option functions the library provides. Turns out the library provides elastic.SetHttpClient that accepts elastic.Doer. The Doer is an interface that http.Client can implement. From here, the answer becomes clear.
So, you have to:
Change your func NewESSink() to accept http Client or elastic Client.
Write stub http Client (implements elastic.Doer).
ESSink
type ESSink struct {
client *elastic.Client
}
func NewESSink(client *elastic.Client) *ESSink {
return &ESSink{client: client}
}
Stub HttpClient
package stubs
import "net/http"
type HTTPClient struct {
Response *http.Response
Error error
}
func (c *HTTPClient) Do(*http.Request) (*http.Response, error) {
return c.Response, c.Error
}
Your testing code
func TestWrite(t *testing.T) {
// set the body and error according to your test case
stubHttpClient := stubs.HTTPClient{
Response: &http.Response{Body: ...},
Error: ...,
}
elasticClient := elastic.NewClient(elastic.SetHttpClient(stubHttpClient))
esSink := NewESSink(elasticClient)
esSink.Write(...)
}
In your production code, you can use http.Client{} when setting ES http client.
I'm trying to implement unit tests in Go for an existing service which uses a connection pool struct and a connection struct from an existing library (call these LibraryPool and LibraryConnection) to connect to an external service.
To use these, the service functions in the main code uses a unique, global instance of the pool, which has a GetConnection() method, like this:
// Current Main Code
var pool LibraryPool // global, instantiated in main()
func someServiceFunction(w http.ResponseWriter, r *http.Request) {
// read request
// ...
conn := pool.GetConnection()
conn.Do("some command")
// write response
// ...
}
func main() {
pool := makePool() // builds and returns a LibraryPool
// sets up endpoints that use the service functions as handlers
// ...
}
I'd like to unit-test these service functions without connecting to the external service, and so I'd like to mock the LibraryPool and LibraryConnection. To allow for this, I was thinking of changing the main code to something like this:
// Tentative New Main Code
type poolInterface interface {
GetConnection() connInterface
}
type connInterface interface {
Do(command string)
}
var pool poolInterface
func someServiceFunction(w http.ResponseWriter, r *http.Request) {
// read request
// ...
conn := pool.GetConnection()
conn.Do("some command")
// write response
// ...
}
func main() {
pool := makePool() // still builds a LibraryPool
}
In the tests, I would use mock implementations MockPool and MockConnection of these interfaces, and the global pool variable would be instantiated using MockPool. I would instantiate this global pool in a setup() function, inside of a TestMain() function.
The problem is that in the new main code, LibraryPool does not properly implement poolInterface, because GetConnection() returns a connInterface instead of a LibraryConnection (even though LibraryConnection is a valid implementation of connInterface).
What would be a good way to approach this kind of testing? The main code is flexible too, by the way.
Well, I'll try to answer by completely explain how I see this design. Sorry in advance if this is too much and not to the point..
Entity / Domain
The core of the app, will include the entity struct, won't import ANY outer layer package, but can be imported by every package (almost)
Application / Use case
The "service". Will be responsible mainly for the app logic, won't know about the transport(http), will "talk" with the DB through interface. Here you can have the domain validation, for example if resource is not found, or text is too short. Anything related to business logic.
transport
Will handle the http request, decode the request, get the service to do his stuff, and encode the response. Here you can return 401 if there is a missing required param in the request, or the user is not authorized, or something...
infrastructure
DB connection
Maybe some http engine and router and stuff.
Totally app-agnostic, don't import any inner package, not even Pseron
For example, let's say we want to do something as simple as insert person to the db.
package person will only include the person struct
package person
type Person struct{
name string
}
func New(name string) Person {
return Person{
name: name,
{
}
About the db, let's say you use sql, I recommend to make a package named sql to handle the repo. (if you use postgress, use 'postgress package...).
The personRepo will get the dbConnection which will be initialized in main and implement DBAndler. only the connection will "talk" with the db directly, the repository main goal is to be gateway to the db, and speak in application-terms. (the connection is app-agnostic)
package sql
type DBAndler interface{
exec(string, ...interface{}) (int64, error)
}
type personRepo struct{
dbHandler DBHandler
}
func NewPersonRepo(dbHandler DBHandler) &personRepo {
return &personRepo{
dbHandler: dbHandler,
}
}
func (p *personRepo) InsertPerson(p person.Person) (int64, error) {
return p.dbHandler.Exec("command to insert person", p)
}
The service will get this repository as a dependancy (as interface) in the initailzer, and will interact with it to accomplish the business logic
package service
type PersonRepo interface{
InsertPerson(person.Person) error
}
type service struct {
repo PersonRepo
}
func New(repo PersonRepo) *service {
return &service{
repo: repo
}
}
func (s *service) AddPerson(name string) (int64, error) {
person := person.New(name)
return s.repo.InsertPerson(person)
}
Your transport handler will be initialized with the service as a dependancy, and he will handle the http request.
package http
type Service interface{
AddPerson(name string) (int64, error)
}
type handler struct{
service Service
}
func NewHandler(s Service) *handler {
return &handler{
service: s,
}
}
func (h *handler) HandleHTTP(w http.ResponseWriter, r *http.Request) {
// read request
// decode name
id, err := h.service.AddPerson(name)
// write response
// ...
}
And in main.go you will tie everything together:
Initialize db connection
Initialize personRepo with this connection
Initialize service with the repo
Initialize the transport with the service
package main
func main() {
pool := makePool()
conn := pool.GetConnection()
// repo
personRepo := sql.NewPersonRepo(conn)
// service
personService := service.New(personRepo)
// handler
personHandler := http.NewPersonHandler(personService)
// Do the rest of the stuff, init the http engine/router by passing this handler.
}
Note that every package struct was initialized with an interface but returned a struct, and also the interfaces were declared in the package which used them, not in the package which implemented them.
This makes it easy to unit test these package. for example, if you want to test the service, you don't need to worry about the http request, just use some 'mock' struct that implements the interface that the service depend on (PersonRepo), and you good to go..
Well, I hope it helped you even a little bit, it may seem confusing at first, but in time you will see how this seems like a large piece of code, but it helps when you need to add functionality or switching the db driver and such.. I recommend you to read about domain driven design in go, and also hexagonal arch.
edit:
In addition, this way you pass the connection to the service, the service doesn't import and use the global DB pool. Honestly, I don't know why it is so common, I guess it has its advantages and it is better to some application, but generally I think that letting your service depend on some interface, without actually know what is going on, is much a better practice.
I come from python and I have been looking for a way to write yests in go. I have come across a few things on SO but they all seem very cumbersome and verbose for something that shpuld be needed all the time.
I am typing on mobile now, will add code later if needed...but for example...
say i have a function that calls smtp.Send somewhere in the middle. how can I easily test this function?
Say i have another one that hits some outside api (needs mocking) and then takes the response and calls something like ioutil.Readall()...how could i make my way through this test function and mock the call to the api and then pass some fake response data when Readall is called?
You can do it by using an interface. For example let's say you have an interface called Mailer:
type Mailer interface {
Send() error
}
Now you can embed a Mailer object into the function that calls the Send method.
type Processor struct {
Mailer
}
func (p *Processor) Process() {
_ = p.Mailer.Send()
}
Now in your test you can create a mock Mailer.
type mockMailer struct{}
//implement the Send on the mockMailer as you wish
p := &Processor{
Mailer: mockMailer,
}
p.Process()
when p.Process reaches the Send method it calls your mocked Send method.
I'm having a test code for checking a web service, and some of the inherited classes brings in HttpService (not sure, which one), requiring me to define an actorRefFactory reference within the test class.
Is there a better way to do this?
Scala 2.11.4, ScalaTest 2.2.1, Spray 1.3.2, Akka 2.3.6
class RestAPITest extends FlatSpec
with Matchers
with ScalatestRouteTest
with SprayJsonSupport
with MyRoute
{
// Without this, we get:
// <<
// Error:(48, 7) class RestAPITest needs to be abstract, since method actorRefFactory in trait HttpService of type => akka.actor.ActorRefFactory is not defined
// <<
//
def actorRefFactory: ActorSystem = system
...
The actorSystem is required by spray since it is based on Akka actors. The idiomatic testing mechanism for spray would be to use the spray-testkit project.
From the spray-testkit documentation:
The basic structure of a test built with spray-testkit is this (expression placeholder in all-caps):
REQUEST ~> ROUTE ~> check {
ASSERTIONS
}
In this template REQUEST is an expression evaluating to an HttpRequest instance. Since both RouteTest traits extend the spray-httpx Request Building trait you have access to its mini-DSL for convenient and concise request construction.
ROUTE is an expression evaluating to a spray-routing Route. You can specify one inline or simply refer to the route structure defined in your service.
The final element of the ~> chain is a check call, which takes a block of assertions as parameter. In this block you define your requirements onto the result produced by your route after having processed the given request. Typically you use one of the defined “inspectors” to retrieve a particular element of the routes response and express assertions against it using the test DSL provided by your test framework. For example, with specs2, in order to verify that your route responds to the request with a status 200 response, you’d use the status inspector and express an assertion like this:
status mustEqual 200
as the error said, you need an actorRefFactory for the actor to spawn in the HTTP service. So go ahead.