qual

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 15, 2018 License: BSD-3-Clause Imports: 10 Imported by: 0

README

Build Status codecov Maintainability

qual - Go package for quality assessment at source code level

Quick start

go get github.com/gregoryv/qual

Add a unit test to your project

func Test_CodeQuality(t *testing.T) {
    qual.Standard(t)
}

or if you are really brave, do

func Test_CodeQuality(t *testing.T) {
    qual.High(t)
}

The predefined tests measure

  • code complexity
  • line width

where the qual.Standard test only checks your package and qual.High also includes vendored code.

Scope

This package helps to improve code readability. Note, it's not measuring the quality of features in your solution. Those are better measured with benchmarks and user experience. The quality of the source code helps developers pass on their intent of their solution to other developers. We do this in various ways

  • documenting
  • tests and examples and most importantly
  • writing readable code

If we can write readable code, documentation can be minimized and that is always good, since developers tend to prefer writing code over documentation.

Assert

This package also provides an assert func for writing clear and concise unittests. Test code in itself if written properly is readable and very contained. It makes a good description in itself if the test should ever fail. However most packages try to solve this by providing short named func for operators within the language. E.g.

assert.Equals(t, a, b, "a and b be should be equal")

This reads fairly well but if you consider adding a couple more of these statements, readability starts to suffer

a, b, c, d := SomeFancyFunc()
assert.Equals(t, a, b, "a and b be should be equal")
assert.NotEquals(t, a, c, "a and c should be different")
assert.NotNil(t, d, "d should not be nil")

and get repetitive. Using the Assert func you can achieve the same thing with

a, b, c, d := SomeFancyFunc()
Assert(t, Vars{a,b,c,d},
  a == b,
  a != c,
  d != nil,
)

As you can see there are no textual descriptions of the different assertions. We don't have to describe a == b with a and b should be equal that is how we read the operator ==. Let's assume the above test fails on the assertion a != c then the error would be printed as

> a, b, c, d := SomeFancyFunc()
  failed assert: a != c
    a = 1
    b = 1
    c = 1
    d = nil

What happens is the assert method parses out the context it's called in and prints the nearest line above it, so we know which statement we are actually testing. After that the failed assertions are listed and finally all the vars that are of interest are printed. More examples are provided in godoc Assert

Documentation

Overview

Package qual implements tests and helpers for writing highly readable tests.

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultWeight = 20 * 60 * time.Second

DefaultWeight is the duration it takes to fix overloaded complexity level. E.g. if complexity is 6 and you've set max to 5 this is the duration it takes to fix the code from 6 to 5.

Functions

func Assert added in v0.2.0

func Assert(t T, v Vars, checks ...bool) (failed bool)
Example
// In this example the Assert call fails to show the output.  The
// line just above Assert(...) will be printed for context if an
// error occurs.
val, err := []byte("an apple"), fmt.Errorf("This is an error")
Assert(t, Vars{val, err},
	len(val) == 10,
	err != nil,
)
Output:
> val, err := []byte("an apple"), fmt.Errorf("This is an error")
  failed assert: len(val) == 10
    val = "an apple"
    err = "This is an error"
Example (MissingSourceCode)

When using the Assert func even though you do not have access to the source code, eg. when doing integration tests a generic output will be given.

os.Rename("assert_example_test.go", "missing.go")
defer os.Rename("missing.go", "assert_example_test.go")

msg := "Verify response status code"
resp, _ := http.Get("http://www.example.com/existing_file")
Assert(t, Vars{resp.StatusCode, msg},
	resp.StatusCode == 200,
)
Output:
  failed assert[0]
    Vars[0] = 404
    Vars[1] = "Verify response status code"
Example (Nil)
var err error
val, err := 9, nil
Assert(t, Vars{val, err},
	val == 9,
	err != nil,
)
Output:
> val, err := 9, nil
  failed assert: err != nil
    val = 9
    err = nil
Example (Oneline)
val, err := 1, fmt.Errorf("This is an error")
Assert(t, Vars{val, err}, val == 2, err == nil)
Output:
> val, err := 1, fmt.Errorf("This is an error")
  failed assert: val == 2
  failed assert: err == nil
    val = 1
    err = "This is an error"

func CyclomaticComplexity

func CyclomaticComplexity(max int, includeVendor bool, t T)

CyclomaticComplexity fails if max is exceeded in any go files of this project.

func FixDuration added in v0.2.1

func FixDuration(complexity, max int) (exp time.Duration)

FixDuration calculates the duration to fix all overloaded complexity. Everything more complex than 14+max is timed as if 14.

func High

func High(t T)

High is the same as Standard, only it includes all vendor source as well.

func LineLength

func LineLength(maxChars, tabSize int, includeVendor bool, t T)

SourceWidth fails if any go file contains lines exceeding maxChars. All lines are considered, source and comments.

func Standard

func Standard(t T)

Standard tests a set of metrics which might be considered necessary for production code. This is very opinionated, but the values are based on community insights from various sources.

Types

type T

type T interface {
	Helper()
	Error(...interface{})
	Errorf(string, ...interface{})
	Log(...interface{})
}

type Vars added in v0.2.0

type Vars []interface{}

Vars groups variables which will be logged on test failures

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL