Golang show that I have only 50% of covering code, and as I see code in main is not covered, I've tried to search but not found anything with explanations how to cover code in main.
main.go
package main
func Sum(x int, y int) int {
return x + y
}
func main() {
Sum(5, 5)
}
main_test.go
package main
import (
"testing"
)
func TestSum(t *testing.T) {
total := Sum(5, 5)
if total != 10 {
t.Fail()
}
}
Test files usually are directly next to the code they test. Depending on the size of your project you don't have to extract your sum function into another package just to test it and it also doesn't have to be public:
main.go
package main
func main() {
sum()
}
func sum() int {
return 5 + 5
}
main_test.go:
package main
import (
"testing"
)
func TestSum(t *testing.T) {
total := sum()
if total != 10 {
t.Fail()
}
}
Related
How to write unit test for the function getAreaFunc() in vs code. Code coverage does not cover the returned function. Can anyone provide a example ?
package main
import "fmt"
func main() {
areaF := getAreaFunc()
res := areaF(2, 4)
fmt.Println(res)
}
func getAreaFunc() func(int, int) int {
return func(x, y int) int {
return x * y
}
}
Code coverage does not cover the returned function
I'm not sure how you implement the unit test, but the returned function of getAreaFunc definitely can be covered by a unit test.
For example:
// main.go
package main
func getAreaFunc() func(int, int) int {
return func(x, y int) int {
return x * y
}
}
// main_test.go
package main
import (
"fmt"
"testing"
)
func TestGetAreaFunc(t *testing.T) {
areaF := getAreaFunc()
res := areaF(2, 4)
fmt.Println(res)
}
Once you execute command go test -cover . you will get 100% coverage in result
I have currently the following function in one file:
func pinExported(pin int) bool {
pinPath := fmt.Sprintf("/sys/class/gpio/gpio%d", pin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
and another code part in the same file which uses the above function which looks like this:
func isGpioPinExported(gpioPin int) bool {
exported := pinExported(gpioPin)
for !exported && (timeOut < timeOutForPinExportInMilliseconds) {
timeOut++
time.Sleep(1 * time.Millisecond)
exported = pinExported(gpioPin)
}
...
So now I'm searching for an elegant way to mock/replace somehow the above pinExported function within my unit tests to test the logic inside isGpioPinExported because the function pinExported is hardware dependent (Raspberry PI).
One solution could be to make the pinExported function a parameter of isGpioPinExported
So defining a function type like this:
type pinExported func(int) int
which means I have to define isGpioPinExported like this:
isGpioPinExported(pinExported pinExported, gpioPin int) bool {
exported := pinExported(gpioPin)
for !exported && (timeOut < timeOutForPinExportInMilliseconds) {
...
}
..
}
Now I can write my unit test and define a mock/fake pinExported without a problem. So far so good. But I have about five or six of such functions which means it would result in putting five or six supplemental parameters to a function like isGpioPinExported which is simply wrong. Apart from that the question is where can I define the default implementation which are used if this is not running under test?
So based on the suggestion of mkopriva I have created an interface which looks like this (now with three functions to see how this really works):
type Raspberry interface {
isPinExported(gpioPin int) bool
valueExist(gpioPin int) bool
directionExist(gpioPin int) bool
}
Furthermore defined a structure to make the implementation for real hardware (Raspberry):
type Rasberry3Plus struct {
}
func (raspberry Rasberry3Plus) valueExist(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d/value", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
func (raspberry Rasberry3Plus) directionExist(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d/direction", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
func (raspberry Rasberry3Plus) isPinExported(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
and the function IsGpioPinExported which uses the above functions looks now like this (This is just an example implementation to see how the mocking testing works):
func IsGpioPinExported(raspberry Raspberry, gpioPin int) bool {
pinExported := raspberry.isPinExported(gpioPin)
valueExist := raspberry.valueExist(gpioPin)
directionExist := raspberry.directionExist(gpioPin)
return valueExist && directionExist && pinExported
}
So now the tests look like this. First I have to define a type (btw: I have decided to go with Mock):
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)
type mockRaspberry struct {
mock.Mock
}
func (raspMock mockRaspberry) isPinExported(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func (raspMock mockRaspberry) valueExist(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func (raspMock mockRaspberry) directionExist(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func Test_ValueTrue_DirectionExistTrue(t *testing.T) {
testObj := new(mockRaspberry)
testObj.On("isPinExported", 5).Return(false)
testObj.On("valueExist", 5).Return(true)
testObj.On("directionExist", 5).Return(true)
exported := IsGpioPinExported(testObj, 5)
assert.Equal(t, false, exported)
}
And now it is simple to test the loigic in function IsGpioPinExported with the appropriate mocked functions with wished result. And finally the main program looks like this:
func main() {
rasberry3Plus := gpio.Rasberry3Plus{}
gpio.IsGpioPinExported(rasberry3Plus, 23)
}
I'm trying to write Go Unit Test using testify mocking library. I was following this blog http://goinbigdata.com/testing-go-code-with-testify/. I have passed the mocked interface to the newCalculator function but still Random1 of Random interface is getting called instead of Random1 function of struct randomMock.
calculator.go
package calculator
type Random interface {
Random1(limit int) int
}
func newCalculator(rnd Random) Random {
return calc{
rnd: rnd,
}
}
type calc struct {
rnd Random
}
func (c calc) Random1(limit int) int {
return limit
}
calculator_test.go
package calculator
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)
type randomMock struct {
mock.Mock
}
func (o randomMock) Random1(limit int) int {
args := o.Called(limit)
return args.Int(0)
}
func TestRandom(t *testing.T) {
rnd := new(randomMock)
rnd.On("Random1", 100).Return(7)
calc := newCalculator(rnd)
assert.Equal(t, 7, calc.Random1(100))
}
Output on running: go test
--- FAIL: TestRandom (0.00s)
calculator_test.go:22:
Error Trace: calculator_test.go:22
Error: Not equal:
expected: 7
actual : 100
Test: TestRandom
FAIL
exit status 1
I got it myself. I was missing the call to the struct rnd first.
func (c calc) Random1(limit int) int {
return c.rnd.Random1(limit)
}
In pursuit of 100% unit test coverage, we have several lines we're trying to test in one of our functions. The relevant function calls out to the runtime package:
// functionName returns a string representing the function name of the function n stack frames above the caller.
// if n = 0, the name of the function calling functionName() will be returned.
func functionName(n int) string {
pc, _, _, ok := runtime.Caller(n + 1)
if !ok {
return "unknown function"
}
me := runtime.FuncForPC(pc)
if me == nil {
return "unknown function"
}
split := strings.Split(me.Name(), ".")
if len(split) == 0 {
return "unknown function"
}
return split[len(split)-1]
}
Specifically, the 3 if statements and their return values are currently untested, because the runtime functions don't appear to be easily manipulated to return the values we want. Our standard response in these cases is to mock out the items in question, but these calls are to package-level functions (rather than methods of an interface) within the runtime package itself.
My first thought was to mock out the runtime token itself by using a structure with Caller() and FuncForPC() methods, assigned to a variable named "runtime" in the test files (so it wouldn't affect the production code flow, since test files are omitted during normal builds). However, this triggers a build error about "runtime" being redeclared within the (global) block.
I know this would be possible if the "runtime" variable were declare in a non-global scope (example masking fmt), but I can't find an elegant way to do so such that it gets masked within the tests, but not within the production code itself. The only way I've thought of is by altering the source of the production code to declare such a variable and replacing it's value in the tests, but this is far from ideal, since it complicates the production code purely for the purposes of testing.
Any ideas?
One solution is to declare variables of those functions you want to mock.
var runtimeCaller = runtime.Caller
var runtimeFuncForPC = runtime.FuncForPC
func functionName(n int) string {
pc, _, _, ok := runtimeCaller(n + 1)
if !ok {
return "unknown function"
}
me := runtimeFuncForPC(pc)
if me == nil {
return "unknown function"
}
split := strings.Split(me.Name(), ".")
if len(split) == 0 {
return "unknown function"
}
return split[len(split)-1]
}
Or if you prefer the dot notation...
var _runtime = struct{
Caller func(skip int) (pc uintptr, file string, line int, ok bool)
FuncForPC func(pc uintptr) *runtime.Func
}{runtime.Caller, runtime.FuncForPC}
func functionName(n int) string {
pc, _, _, ok := _runtime.Caller(n + 1)
if !ok {
return "unknown function"
}
me := _runtime.FuncForPC(pc)
if me == nil {
return "unknown function"
}
split := strings.Split(me.Name(), ".")
if len(split) == 0 {
return "unknown function"
}
return split[len(split)-1]
}
And in your tests, before running functionName, you can set the variables/fields to mock implementations. And if other tests may cause the functionName to be called beware of concurrent access... I don't think there is much else you can do without changing the existing code significantly.
On the reliability of programs. Edsger W. Dijkstra
The first moral of the story is that program testing can be used very
effectively to show the presence of bugs but never to show their
absence.
Let's read your code. Go type int is a 32- or 64-bit signed integer. Therefore, consider,
funcname.go:
package main
import (
"fmt"
"runtime"
"strings"
)
// functionName returns a string representing the function name of the function n stack frames above the caller.
// if n = 0, the name of the function calling functionName() will be returned.
func functionName(n int) string {
pc, _, _, ok := runtime.Caller(n + 1)
if !ok {
return "unknown function"
}
me := runtime.FuncForPC(pc)
if me == nil {
return "unknown function"
}
split := strings.Split(me.Name(), ".")
if len(split) == 0 {
return "unknown function"
}
return split[len(split)-1]
}
func main() {
for skip := -4; skip <= 4; skip++ {
fn := functionName(skip)
fmt.Println(functionName(0), skip, fn)
}
const (
sizeInt = 32 << (^uint(0) >> 63)
maxInt = 1<<(sizeInt-1) - 1
minInt = -1 << (sizeInt - 1)
)
for _, skip := range []int{minInt, maxInt} {
fn := functionName(skip)
fmt.Println(functionName(0), skip, fn)
}
}
Output:
$ go run funcname.go
main -4 skipPleaseUseCallersFrames
main -3 skipPleaseUseCallersFrames
main -2 skipPleaseUseCallersFrames
main -1 functionName
main 0 main
main 1 main
main 2 goexit
main 3 unknown function
main 4 unknown function
main -9223372036854775808 skipPleaseUseCallersFrames
main 9223372036854775807 skipPleaseUseCallersFrames
$
It looks like a bug in functionName to me. What did your coverage testing say about this?
Reading your code there appears to be no reliable way to detect the return of an error value. One way would be to return an empty string. If you want to use a special value such as "unknown function" then provide a value to check against. For example,
const functionUnknown = "unknown function"
func functionName(n int) string {
pc, file, line, ok := runtime.Caller(n + 1)
if !ok {
return functionUnknown
}
// . . .
}
func main() {
fn := functionName(0)
if fn == functionUnknown {
// handle error
}
}
What did your coverage testing say about this?
I'm trying to get a grasp on goroutines. Take this code:
package main
import "fmt"
var (
b1 []float64
b2 []float64
)
func main() {
go fill(&b1, 10)
go fill(&b2, 10)
fmt.Println(b1,b2)
var s string
fmt.Scanln(&s)
}
func fill(a *[]float64, n int) {
for i:=0; i<n; i++ {
*a = append(*a, rand.Float64()*100)
}
}
As you see, I'm trying to fill two slices. But when run this way (with go fill()), it prints two empty slices. Why is this not working?
Any goroutines you start aren't guaranteed to have finished (or even started!) until you've explicitly waited on them using a sync.WaitGroup, channel, or other mechanism. This works:
package main
import (
"fmt"
"math/rand"
"sync"
)
var (
b1 []float64
b2 []float64
)
func main() {
wg := new(sync.WaitGroup)
wg.Add(2)
go fill(&b1, 10, wg)
go fill(&b2, 10, wg)
wg.Wait()
fmt.Println(b1)
fmt.Println(b2)
}
func fill(a *[]float64, n int, wg *sync.WaitGroup) {
for i := 0; i < n; i++ {
*a = append(*a, rand.Float64()*100)
}
wg.Done()
}
(Just speaking of style, if it were me I'd make this function return the enlarged slice so it's similar to append() itself, and Go's Code Review Comments suggest passing values, though it's not at all unconventional to extend a slice passed as a pointer receiver ("this") parameter.)