There's been a lot of debates on whether TDD is dead or not! I strongly believe that TDD is very essential in any serious Software Development endeavor, especially for any team which is currently embracing MICRO-services architecture or might seek to transition to Micro-services later.
TDD somewhat will drive you to work out better and better system design rather than just focus on increasing Code Coverage as a vanity metric. The more you aim to improve Testability and TDD compliance in every single piece of your software, the easier you can extend or modify any functionalities in your system.
I'm gonna share some pieces of codes to help illustrate my points regarding how different they are in practiceLet's dive into those differences
//Non-Test
package client
import (
"bitbucket.org/sakariai/sakari/proto"
"go.elastic.co/apm/module/apmgrpc"
"google.golang.org/grpc"
)
type Volante struct {
proto.VolanteClient
conn *grpc.ClientConn
}
func NewInternalVolanteClient(address string) (*Volante, error) {
client, disconnection, err := withInfo(address)
if err != nil {
return nil, err
}
vl := &Volante{VolanteClient: client, conn: disconnection}
return vl, nil
}
func withInfo(address string) (proto.VolanteClient, *grpc.ClientConn, error) {
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithUnaryInterceptor(apmgrpc.NewUnaryClientInterceptor()))
if err != nil {
return nil, nil, err
}
client := proto.NewVolanteClient(conn)
return client, conn, nil
}
func (v Volante) Close() error {
return v.conn.Close()
}
And...
//Test Driven
package client
import (
"io"
"bitbucket.org/sakariai/sakari/proto"
"go.elastic.co/apm/module/apmgrpc"
"google.golang.org/grpc"
)
type Connector func(string) (proto.VolanteClient, io.Closer, error)
//go:generate mockgen -destination mock_volante.go -package=client bitbucket.org/sakariai/sakari/proto VolanteClient
type Volante struct {
proto.VolanteClient
conn io.Closer
address string
}
var DefaultConnector = withInfo
func NewInternalVolanteClient(address string, cn Connector) (*Volante, error) {
client, disconnection, err := cn(address)
if err != nil {
return nil, err
}
vl := &Volante{VolanteClient: client, conn: disconnection}
return vl, nil
}
//For non-test adoption
func DefaultVolante(address string) (*Volante, error) {
return NewInternalVolanteClient(address, DefaultConnector)
}
//Simlar above
func withInfo(address string) (proto.VolanteClient, io.Closer, error) {
...
}
func (v Volante) Close() error {
return v.conn.Close()
}
* The first approach is not easy to be utilized for other companies if they need to write (unit) tests for their project. Because *grpc.ClientConn is not friendly in Close() function
* By having connector which returns 2 interfaces(io.Closer interface replaces grpc.Conn Struct), which are natural for mocking purposes in an outer package. With this implementation, NewInternalVolanteClient is easy to accommodate any future need for further development regarding test.
func testConnector(t *testing.Test){
mockConnector := func(address string) {
return mockProtoVolanteClient, mockIo.Closer, nil
}
volante := NewInternalVolanteClient("volante", mockConnector)
...
}
I'm pretty sure, Volante variable is pretty comfortable to function in your test environment.
Let's rock to be TEST DRIVEN DEVELOPERLet's rock to be TEST DRIVE DEVELOPER
I'm really impressed with your writing skills, as smart as the structure of your weblog.
ReplyDeleteGoLand Full Crack
Waves v12 Complete Crack
Developed by NetEnt amounts to more than 200 and there are lots of|there are numerous} of them which have been among the many most popular for on-line on line casino players since their release. The PowerUP Roulette live on line casino sport 바카라 사이트 show is a highly anticipated take on the classic Roulette sport, with up to as} 5 PowerUP bonus rounds providing extra chances to win. The greatest video poker video games with your favourite pay tables, starting at 5 cent denomination.
ReplyDelete