Golang logo

Property based testing in golang with quick

In a previous prost, I explained property based testing. In this post we’ll see a simple example using golang’s built-in quick package.

Let assume we’re building the same bank transfer code as described in the dotnet FsCheck earlier post.

Here’s the golang equivalent of the test:

package goquickcheckexample

import (
	"testing"
	"testing/quick"
)

func TestProperties(t *testing.T) {
	bank := BuggyBank{}
	properties := func(StartBalanceA int, StartBalanceB int, TransferAmount int) bool {
		bank.BalanceOfAccountA = StartBalanceA
		bank.BalanceOfAccountB = StartBalanceB
		err := bank.Transfer(TransferAmount)
		if err != nil {
			//Transfer failed
			balancesChanged := (bank.BalanceOfAccountA != StartBalanceA) || (bank.BalanceOfAccountB != StartBalanceB)
			if balancesChanged {
				t.Log("Balances changed on failed transfer")
			}
			return !balancesChanged
		}
		//Transfer succeeded
		balanceAIsNonNegative := bank.BalanceOfAccountA >= 0
		balanceAChanged := bank.BalanceOfAccountA != StartBalanceA
		balanceBchanged := bank.BalanceOfAccountB != StartBalanceB
		if !balanceAIsNonNegative {
			t.Log("Balance of A ended negative")
		}
		if !balanceAChanged {
			t.Log("Balance of A did not change")
		}
		if !balanceBchanged {
			t.Log("Balance of B did not change")
		}
		return balanceAIsNonNegative && balanceAChanged && balanceBchanged
	}

	c := quick.Config{MaxCount: 1000000}
	if err := quick.Check(properties, &c); err != nil {
		t.Error(err)
	}
}

Note: If you want all test runs to use the same set of random numbers then use: c := quick.Config{MaxCount: 1000000, Rand: rand.New(rand.NewSource(0))}

When I ran the test, it detected a defect: Transfers succeed even when the source account’s balance is insufficient:

bank_test.go:28: Balance of A ended negative
bank_test.go:41: #2: failed on input 6319534437456565100, -3125004238116898490, 8226184717426742479

After fixing that bug, it detected a defect: The code allowed transferring negative amounts:

bank_test.go:34: Balance of A ended negative
bank_test.go:47: #22: failed on input 5995030153294015290, -7891513722668943486, -3464545538278061921

While analyzing this defect we notice yet another one: This code is not safe against integer overflow.