Repository: coreruleset/go-ftw
Pull request #90 (2022-10-06 02:10:40)

test: enhance general coverage
In the spirit of getting better coverage, this PR migrates tests to testify.

- move tests to testify
- achieve coverage > 80%

Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org>


Patch:
diff --git a/go.mod b/go.mod
index cfb679e..fc0053c 100644
--- a/go.mod
+++ b/go.mod
@@ -11,6 +11,7 @@ require (
 	github.com/kyokomi/emoji v2.2.4+incompatible
 	github.com/rs/zerolog v1.22.0
 	github.com/spf13/cobra v1.1.3
+	github.com/stretchr/testify v1.5.1
 	github.com/yargevad/filepathx v1.0.0
 	golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
 )
@@ -18,6 +19,7 @@ require (
 require (
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver v1.5.0 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/fatih/color v1.11.0 // indirect
 	github.com/fsnotify/fsnotify v1.4.9 // indirect
 	github.com/huandu/xstrings v1.3.2 // indirect
@@ -29,8 +31,8 @@ require (
 	github.com/mitchellh/mapstructure v1.4.1 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
 	github.com/pelletier/go-toml v1.9.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
-	github.com/stretchr/testify v1.5.1 // indirect
 	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
 	golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect


Test patch:
diff --git a/check/base_test.go b/check/base_test.go
index ff0595c..dc34681 100644
--- a/check/base_test.go
+++ b/check/base_test.go
@@ -4,6 +4,8 @@ import (
 	"sort"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 	"github.com/coreruleset/go-ftw/test"
 )
@@ -25,16 +27,12 @@ mode: "cloud"
 
 func TestNewCheck(t *testing.T) {
 	err := config.NewConfigFromString(yamlNginxConfig)
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 
 	c := NewCheck(config.FTWConfig)
 
 	for _, text := range c.overrides.Ignore {
-		if text != "Ignore Me" {
-			t.Errorf("Well, didn't match Ignore Me")
-		}
+		assert.Equal(t, text, "Ignore Me", "Well, didn't match Ignore Me")
 	}
 
 	to := test.Output{
@@ -46,49 +44,33 @@ func TestNewCheck(t *testing.T) {
 	}
 	c.SetExpectTestOutput(&to)
 
-	if c.expected.ExpectError != true {
-		t.Error("Problem setting expected output")
-	}
+	assert.True(t, c.expected.ExpectError, "Problem setting expected output")
 
 	c.SetNoLogContains("nologcontains")
 
-	if c.expected.NoLogContains != "nologcontains" {
-		t.Error("PRoblem setting nologcontains")
-	}
+	assert.Equal(t, c.expected.NoLogContains, "nologcontains", "Problem setting nologcontains")
 }
 
 func TestForced(t *testing.T) {
 	err := config.NewConfigFromString(yamlNginxConfig)
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 
 	c := NewCheck(config.FTWConfig)
 
-	if !c.ForcedIgnore("942200-1") {
-		t.Errorf("Can't find ignored value")
-	}
+	assert.True(t, c.ForcedIgnore("942200-1"), "Can't find ignored value")
 
-	if c.ForcedFail("1245") {
-		t.Errorf("Value should not be found")
-	}
+	assert.False(t, c.ForcedFail("1245"), "Value should not be found")
 
-	if c.ForcedPass("1245") {
-		t.Errorf("Value should not be found")
-	}
+	assert.False(t, c.ForcedPass("1245"), "Value should not be found")
 }
 
 func TestCloudMode(t *testing.T) {
 	err := config.NewConfigFromString(yamlCloudConfig)
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 
 	c := NewCheck(config.FTWConfig)
 
-	if c.CloudMode() != true {
-		t.Errorf("couldn't detect cloud mode")
-	}
+	assert.True(t, c.CloudMode(), "couldn't detect cloud mode")
 
 	status := []int{200, 301}
 	c.SetExpectStatus(status)
@@ -98,9 +80,8 @@ func TestCloudMode(t *testing.T) {
 
 	cloudStatus := c.expected.Status
 	sort.Ints(cloudStatus)
-	if res := sort.SearchInts(cloudStatus, 403); res == 0 {
-		t.Errorf("couldn't find expected 403 status in %#v -> %d", cloudStatus, res)
-	}
+	res := sort.SearchInts(cloudStatus, 403)
+	assert.Equalf(t, 2, res, "couldn't find expected 403 status in %#v -> %d", cloudStatus, res)
 
 	c.SetLogContains("")
 	c.SetNoLogContains("no log contains")
@@ -115,8 +96,6 @@ func TestCloudMode(t *testing.T) {
 			found = true
 		}
 	}
-	if !found {
-		t.Errorf("couldn't find expected 200 status\n")
-	}
+	assert.True(t, found, "couldn't find expected 200 status")
 
 }
diff --git a/check/error_test.go b/check/error_test.go
index af661c7..eb45a5e 100644
--- a/check/error_test.go
+++ b/check/error_test.go
@@ -4,6 +4,8 @@ import (
 	"errors"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 )
 
@@ -25,32 +27,23 @@ var expectedFailTests = []struct {
 
 func TestAssertResponseErrorOK(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
+	assert.NoError(t, err)
 
-	if err != nil {
-		t.Errorf("Failed!")
-	}
 	c := NewCheck(config.FTWConfig)
 	for _, e := range expectedOKTests {
 		c.SetExpectError(e.expected)
-		if c.AssertExpectError(e.err) != e.expected {
-			t.Errorf("Failed !")
-		}
+		assert.Equal(t, e.expected, c.AssertExpectError(e.err))
 	}
 }
 
 func TestAssertResponseFail(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
-
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	c := NewCheck(config.FTWConfig)
 
 	for _, e := range expectedFailTests {
 		c.SetExpectError(e.expected)
-		if c.AssertExpectError(e.err) && e.expected {
-			t.Errorf("Failed !")
-		}
+		assert.False(t, c.AssertExpectError(e.err))
 	}
 }
diff --git a/check/logs_test.go b/check/logs_test.go
index 6ebbf2c..06204fc 100644
--- a/check/logs_test.go
+++ b/check/logs_test.go
@@ -4,6 +4,8 @@ import (
 	"os"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 	"github.com/coreruleset/go-ftw/utils"
 )
@@ -16,9 +18,8 @@ var logText = `[Tue Jan 05 02:21:09.637165 2021] [:error] [pid 76:tid 1396834345
 
 func TestAssertLogContainsOK(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
+
 	logName, _ := utils.CreateTempFileWithContent(logText, "test-*.log")
 	defer os.Remove(logName)
 	config.FTWConfig.LogFile = logName
@@ -26,14 +27,13 @@ func TestAssertLogContainsOK(t *testing.T) {
 	c := NewCheck(config.FTWConfig)
 
 	c.SetLogContains(`id "920300"`)
+	assert.True(t, c.AssertLogContains(), "did not find expected content 'id \"920300\"'")
+	c.SetLogContains(`SOMETHING`)
+	assert.False(t, c.AssertLogContains(), "found something that is not there")
 
-	// c.SetNoLogContains(`Something that is not there`)
-
-	if !c.AssertLogContains() {
-		t.Errorf("Failed !")
-	}
+	c.SetNoLogContains("SOMETHING")
+	assert.True(t, c.AssertNoLogContains(), "found something that is not there")
+	c.SetNoLogContains(`id "920300"`)
+	assert.False(t, c.AssertNoLogContains(), "did not find expected content")
 
-	// if !c.AssertNoLogContains() {
-	// 	t.Errorf("Failed !")
-	// }
 }
diff --git a/check/response_test.go b/check/response_test.go
index 4428031..81418ab 100644
--- a/check/response_test.go
+++ b/check/response_test.go
@@ -3,6 +3,8 @@ package check
 import (
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 )
 
@@ -22,29 +24,22 @@ var expectedResponseFailTests = []struct {
 
 func TestAssertResponseTextErrorOK(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
+	assert.NoError(t, err)
 
-	if err != nil {
-		t.Errorf("Failed!")
-	}
 	c := NewCheck(config.FTWConfig)
 	for _, e := range expectedResponseOKTests {
 		c.SetExpectResponse(e.expected)
-		if !c.AssertResponseContains(e.response) {
-			t.Errorf("Failed !")
-		}
+		assert.Truef(t, c.AssertResponseContains(e.response), "unexpected response: %v", e.response)
 	}
 }
 
 func TestAssertResponseTextFailOK(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
+
 	c := NewCheck(config.FTWConfig)
 	for _, e := range expectedResponseFailTests {
 		c.SetExpectResponse(e.expected)
-		if c.AssertResponseContains(e.response) {
-			t.Errorf("Failed !")
-		}
+		assert.Falsef(t, c.AssertResponseContains(e.response), "response shouldn't contain text %v", e.response)
 	}
 }
diff --git a/check/status_test.go b/check/status_test.go
index 8656c56..4c488e0 100644
--- a/check/status_test.go
+++ b/check/status_test.go
@@ -3,6 +3,8 @@ package check
 import (
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 )
 
@@ -25,32 +27,24 @@ var statusFailTests = []struct {
 
 func TestStatusOK(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	c := NewCheck(config.FTWConfig)
 
 	for _, expected := range statusOKTests {
 		c.SetExpectStatus(expected.expectedStatus)
-		if !c.AssertStatus(expected.status) {
-			t.Errorf("Failed !")
-		}
+		assert.True(t, c.AssertStatus(expected.status))
 	}
 }
 
 func TestStatusFail(t *testing.T) {
 	err := config.NewConfigFromString(yamlApacheConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	c := NewCheck(config.FTWConfig)
 
 	for _, expected := range statusFailTests {
 		c.SetExpectStatus(expected.expectedStatus)
-		if c.AssertStatus(expected.status) {
-			t.Errorf("Failed !")
-		}
+		assert.False(t, c.AssertStatus(expected.status))
 	}
 }
diff --git a/config/config_test.go b/config/config_test.go
index 45952b7..a2ce2cd 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -2,10 +2,10 @@ package config
 
 import (
 	"os"
-	"reflect"
-	"strings"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/utils"
 )
 
@@ -37,40 +37,24 @@ func TestNewConfigBadFileConfig(t *testing.T) {
 	filename, _ := utils.CreateTempFileWithContent(jsonConfig, "test-*.yaml")
 	defer os.Remove(filename)
 	err := NewConfigFromFile(filename)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 }
 
 func TestNewConfigConfig(t *testing.T) {
 	filename, _ := utils.CreateTempFileWithContent(yamlConfig, "test-*.yaml")
 
 	err := NewConfigFromFile(filename)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
-
-	if len(FTWConfig.TestOverride.Ignore) == 0 {
-		t.Errorf("Failed! Len must be > 0")
-	}
-
-	if reflect.ValueOf(FTWConfig.TestOverride.Input).IsZero() {
-		t.Errorf("Failed! Input must not be empty")
-	}
+	assert.NoError(t, err)
+	assert.NotEmpty(t, FTWConfig.TestOverride.Input, "Ignore list must not be empty")
 
 	for id, text := range FTWConfig.TestOverride.Ignore {
-		if !strings.Contains(id, "920400-1") {
-			t.Errorf("Looks like we could not find item to ignore")
-		}
-		if text != "This test result must be ignored" {
-			t.Errorf("Text doesn't match")
-		}
+		assert.Contains(t, id, "920400-1", "Looks like we could not find item to ignore")
+		assert.Equal(t, "This test result must be ignored", text, "Text doesn't match")
 	}
 
 	overrides := FTWConfig.TestOverride.Input
-	if overrides.DestAddr != nil && *overrides.DestAddr != "httpbin.org" {
-		t.Errorf("Looks like we are not overriding destination!")
-	}
+	assert.NotNil(t, overrides.DestAddr, "Looks like we are not overriding destination address")
+	assert.Equal(t, "httpbin.org", *overrides.DestAddr, "Looks like we are not overriding destination address")
 }
 
 func TestNewConfigBadConfig(t *testing.T) {
@@ -78,9 +62,7 @@ func TestNewConfigBadConfig(t *testing.T) {
 	defer os.Remove(filename)
 	_ = NewConfigFromFile(filename)
 
-	if FTWConfig == nil {
-		t.Errorf("Failed !")
-	}
+	assert.NotNil(t, FTWConfig)
 }
 
 func TestNewConfigDefaultConfig(t *testing.T) {
@@ -93,23 +75,17 @@ func TestNewConfigDefaultConfig(t *testing.T) {
 
 	_ = NewConfigFromFile("")
 
-	if FTWConfig == nil {
-		t.Errorf("Failed !")
-	}
+	assert.NotNil(t, FTWConfig)
 }
 
 func TestNewConfigFromString(t *testing.T) {
 	err := NewConfigFromString(yamlConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 }
 
 func TestNewEnvConfigFromString(t *testing.T) {
 	err := NewConfigFromString(yamlConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 }
 
 func TestNewConfigFromEnv(t *testing.T) {
@@ -117,67 +93,52 @@ func TestNewConfigFromEnv(t *testing.T) {
 	os.Setenv("FTW_LOGFILE", "kaonf")
 
 	err := NewConfigFromEnv()
+	assert.NoError(t, err)
 
-	if err != nil {
-		t.Error(err)
-	}
-
-	if FTWConfig.LogFile != "kaonf" {
-		t.Errorf(FTWConfig.LogFile)
-	}
+	assert.Equal(t, "kaonf", FTWConfig.LogFile)
 }
 
 func TestNewConfigFromEnvHasDefaults(t *testing.T) {
-	if err := NewConfigFromEnv(); err != nil {
-		t.Error(err)
-	}
+	err := NewConfigFromEnv()
+	assert.NoError(t, err)
+
+	assert.Equalf(t, DefaultRunMode, FTWConfig.RunMode,
+		"unexpected default value '%s' for run mode", FTWConfig.RunMode)
+	assert.Equalf(t, DefaultLogMarkerHeaderName, FTWConfig.LogMarkerHeaderName,
+		"unexpected default value '%s' for logmarkerheadername", FTWConfig.LogMarkerHeaderName)
 
-	if FTWConfig.RunMode != DefaultRunMode {
-		t.Errorf("unexpected default value '%s' for run mode", FTWConfig.RunMode)
-	}
-	if FTWConfig.LogMarkerHeaderName != DefaultLogMarkerHeaderName {
-		t.Errorf("unexpected default value '%s' for logmarkerheadername", FTWConfig.LogMarkerHeaderName)
-	}
 }
 
 func TestNewConfigFromFileHasDefaults(t *testing.T) {
 	filename, _ := utils.CreateTempFileWithContent(yamlConfig, "test-*.yaml")
 	defer os.Remove(filename)
 
-	if err := NewConfigFromFile(filename); err != nil {
-		t.Error(err)
-	}
+	err := NewConfigFromFile(filename)
+	assert.NoError(t, err)
 
-	if FTWConfig.RunMode != DefaultRunMode {
-		t.Errorf("unexpected default value '%s' for run mode", FTWConfig.RunMode)
-	}
-	if FTWConfig.LogMarkerHeaderName != DefaultLogMarkerHeaderName {
-		t.Errorf("unexpected default value '%s' for logmarkerheadername", FTWConfig.LogMarkerHeaderName)
-	}
+	assert.Equalf(t, DefaultRunMode, FTWConfig.RunMode,
+		"unexpected default value '%s' for run mode", FTWConfig.RunMode)
+	assert.Equalf(t, DefaultLogMarkerHeaderName, FTWConfig.LogMarkerHeaderName,
+		"unexpected default value '%s' for logmarkerheadername", FTWConfig.LogMarkerHeaderName)
 }
 
 func TestNewConfigFromStringHasDefaults(t *testing.T) {
-	if err := NewConfigFromString(""); err != nil {
-		t.Error(err)
-	}
+	err := NewConfigFromString("")
+	assert.NoError(t, err)
 
-	if FTWConfig.RunMode != DefaultRunMode {
-		t.Errorf("unexpected default value '%s' for run mode", FTWConfig.RunMode)
-	}
-	if FTWConfig.LogMarkerHeaderName != DefaultLogMarkerHeaderName {
-		t.Errorf("unexpected default value '%s' for logmarkerheadername", FTWConfig.LogMarkerHeaderName)
-	}
+	assert.Equalf(t, DefaultRunMode, FTWConfig.RunMode,
+		"unexpected default value '%s' for run mode", FTWConfig.RunMode)
+	assert.Equalf(t, DefaultLogMarkerHeaderName, FTWConfig.LogMarkerHeaderName,
+		"unexpected default value '%s' for logmarkerheadername", FTWConfig.LogMarkerHeaderName)
 }
 
 func TestNewConfigFromFileRunMode(t *testing.T) {
 	filename, _ := utils.CreateTempFileWithContent(yamlCloudConfig, "test-*.yaml")
 	defer os.Remove(filename)
 
-	if err := NewConfigFromFile(filename); err != nil {
-		t.Error(err)
-	}
+	err := NewConfigFromFile(filename)
+	assert.NoError(t, err)
 
-	if FTWConfig.RunMode != CloudRunMode {
-		t.Errorf("unexpected value '%s' for run mode, expected '%s;", FTWConfig.RunMode, CloudRunMode)
-	}
+	assert.Equalf(t, CloudRunMode, FTWConfig.RunMode,
+		"unexpected value '%s' for run mode, expected '%s;", FTWConfig.RunMode, CloudRunMode)
 }
diff --git a/ftwhttp/client_test.go b/ftwhttp/client_test.go
index 6ccaf45..59cf6bb 100644
--- a/ftwhttp/client_test.go
+++ b/ftwhttp/client_test.go
@@ -2,14 +2,14 @@ package ftwhttp
 
 import (
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestNewClient(t *testing.T) {
 	c := NewClient(NewClientConfig())
 
-	if c.Jar == nil {
-		t.Logf("Error creating Client")
-	}
+	assert.NotNil(t, c.Jar, "Error creating Client")
 }
 
 func TestConnectDestinationHTTPS(t *testing.T) {
@@ -22,13 +22,8 @@ func TestConnectDestinationHTTPS(t *testing.T) {
 	c := NewClient(NewClientConfig())
 
 	err := c.NewConnection(*d)
-	if err != nil {
-		t.Logf("This should not error")
-	}
-
-	if c.Transport.protocol != "https" {
-		t.Logf("Error connecting to example.com using https")
-	}
+	assert.NoError(t, err, "This should not error")
+	assert.Equal(t, "https", c.Transport.protocol, "Error connecting to example.com using https")
 }
 
 func TestDoRequest(t *testing.T) {
@@ -43,15 +38,11 @@ func TestDoRequest(t *testing.T) {
 	req := generateBaseRequestForTesting()
 
 	err := c.NewConnection(*d)
-	if err != nil {
-		t.Logf("This should not error")
-	}
+	assert.NoError(t, err, "This should not error")
 
 	_, err = c.Do(*req)
 
-	if err == nil {
-		t.Logf("This should return error")
-	}
+	assert.Error(t, err, "This should return error")
 }
 
 func TestGetTrackedTime(t *testing.T) {
@@ -75,9 +66,7 @@ func TestGetTrackedTime(t *testing.T) {
 	req := NewRequest(rl, h, data, true)
 
 	err := c.NewConnection(*d)
-	if err != nil {
-		t.Logf("This should not error")
-	}
+	assert.NoError(t, err, "This should not error")
 
 	c.StartTrackingTime()
 
@@ -85,19 +74,13 @@ func TestGetTrackedTime(t *testing.T) {
 
 	c.StopTrackingTime()
 
-	if err != nil {
-		t.Logf("This should not error")
-	}
+	assert.NoError(t, err, "This should not error")
 
-	if resp.Parsed.StatusCode != 200 {
-		t.Logf("Error in calling website")
-	}
+	assert.Equal(t, 200, resp.Parsed.StatusCode, "Error in calling website")
 
 	rtt := c.GetRoundTripTime()
 
-	if rtt.RoundTripDuration() < 0 {
-		t.Logf("Error getting RTT")
-	}
+	assert.GreaterOrEqual(t, int(rtt.RoundTripDuration()), 0, "Error getting RTT")
 }
 
 func TestClientMultipartFormDataRequest(t *testing.T) {
@@ -130,10 +113,7 @@ Some-file-test-here
 	req := NewRequest(rl, h, data, true)
 
 	err := c.NewConnection(*d)
-
-	if err != nil {
-		t.Logf("This should not error")
-	}
+	assert.NoError(t, err, "This should not error")
 
 	c.StartTrackingTime()
 
@@ -141,87 +121,55 @@ Some-file-test-here
 
 	c.StopTrackingTime()
 
-	if err != nil {
-		t.Logf("This should not error")
-	}
-
-	if resp.Parsed.StatusCode != 200 {
-		t.Logf("Error in calling website")
-	}
+	assert.NoError(t, err, "This should not error")
+	assert.Equal(t, 200, resp.Parsed.StatusCode, "Error in calling website")
 
 }
 
 func TestNewConnectionCreatesTransport(t *testing.T) {
 	c := NewClient(NewClientConfig())
-	if c.Transport != nil {
-		t.Errorf("Transport not expected to initialized yet")
-	}
+	assert.Nil(t, c.Transport, "Transport not expected to initialized yet")
 
 	server := testServer()
 	d, err := DestinationFromString(server.URL)
-	if err != nil {
-		t.Errorf("Failed to construct destination from test server")
-	}
-	if err := c.NewConnection(*d); err != nil {
-		t.Errorf("Failed to create new connection")
-	}
-	if c.Transport == nil {
-		t.Errorf("Transport expected to be initialized")
-	}
-	if c.Transport.connection == nil {
-		t.Errorf("Connection expected to be initialized")
-	}
+	assert.NoError(t, err, "Failed to construct destination from test server")
 
+	err = c.NewConnection(*d)
+	assert.NoError(t, err, "Failed to create new connection")
+	assert.NotNil(t, c.Transport, "Transport expected to be initialized")
+	assert.NotNil(t, c.Transport.connection, "Connection expected to be initialized")
 }
 
 func TestNewOrReusedConnectionCreatesTransport(t *testing.T) {
 	c := NewClient(NewClientConfig())
-	if c.Transport != nil {
-		t.Errorf("Transport not expected to initialized yet")
-	}
+	assert.Nil(t, c.Transport, "Transport not expected to initialized yet")
 
 	server := testServer()
 	d, err := DestinationFromString(server.URL)
-	if err != nil {
-		t.Errorf("Failed to construct destination from test server")
-	}
-	if err := c.NewOrReusedConnection(*d); err != nil {
-		t.Errorf("Failed to create new connection")
-	}
-	if c.Transport == nil {
-		t.Errorf("Transport expected to be initialized")
-	}
-	if c.Transport.connection == nil {
-		t.Errorf("Connection expected to be initialized")
-	}
+	assert.NoError(t, err, "Failed to construct destination from test server")
+
+	err = c.NewOrReusedConnection(*d)
+	assert.NoError(t, err, "Failed to create new or to reuse connection")
+	assert.NotNil(t, c.Transport, "Transport expected to be initialized")
+	assert.NotNil(t, c.Transport.connection, "Connection expected to be initialized")
 }
 
 func TestNewOrReusedConnectionReusesTransport(t *testing.T) {
 	c := NewClient(NewClientConfig())
-	if c.Transport != nil {
-		t.Errorf("Transport not expected to initialized yet")
-	}
+	assert.Nil(t, c.Transport, "Transport not expected to initialized yet")
 
 	server := testServer()
 	d, err := DestinationFromString(server.URL)
-	if err != nil {
-		t.Errorf("Failed to construct destination from test server")
-	}
-	if err := c.NewOrReusedConnection(*d); err != nil {
-		t.Errorf("Failed to create new connection")
-	}
-	if c.Transport == nil {
-		t.Errorf("Transport expected to be initialized")
-	}
-	if c.Transport.connection == nil {
-		t.Errorf("Connection expected to be initialized")
-	}
+	assert.NoError(t, err, "Failed to construct destination from test server")
+
+	err = c.NewOrReusedConnection(*d)
+	assert.NoError(t, err, "Failed to create new or to reuse connection")
+	assert.NotNil(t, c.Transport, "Transport expected to be initialized")
+	assert.NotNil(t, c.Transport.connection, "Connection expected to be initialized")
 
 	begin := c.Transport.duration.begin
-	if err := c.NewOrReusedConnection(*d); err != nil {
-		t.Errorf("Failed to reuse connection")
-	}
-	if c.Transport.duration.begin != begin {
-		t.Errorf("Transport must not be reinitialized when reusing connection")
-	}
+	err = c.NewOrReusedConnection(*d)
+	assert.NoError(t, err, "Failed to reuse connection")
+
+	assert.Equal(t, begin, c.Transport.duration.begin, "Transport must not be reinitialized when reusing connection")
 }
diff --git a/ftwhttp/connection_test.go b/ftwhttp/connection_test.go
index 5df6b24..b5d25ce 100644
--- a/ftwhttp/connection_test.go
+++ b/ftwhttp/connection_test.go
@@ -1,6 +1,10 @@
 package ftwhttp
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
 
 func TestDestinationFromString(t *testing.T) {
 
@@ -19,7 +23,5 @@ func TestMultipleRequestTypes(t *testing.T) {
 	data := []byte(`test=me&one=two`)
 	req = NewRequest(rl, h, data, true)
 
-	if !req.WithAutoCompleteHeaders() {
-		t.Error("Set Autocomplete headers error ")
-	}
+	assert.True(t, req.WithAutoCompleteHeaders(), "Set Autocomplete headers error ")
 }
diff --git a/ftwhttp/header_test.go b/ftwhttp/header_test.go
index 3efd1af..5869e5b 100644
--- a/ftwhttp/header_test.go
+++ b/ftwhttp/header_test.go
@@ -12,6 +12,8 @@ import (
 	"bytes"
 	"io"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 var headerWriteTests = []struct {
@@ -52,9 +54,7 @@ func TestHeaderWriteBytes(t *testing.T) {
 	var buf bytes.Buffer
 	for i, test := range headerWriteTests {
 		_ = test.h.WriteBytes(&buf)
-		if buf.String() != test.expected {
-			t.Errorf("#%d:\n got: %q\nwant: %q", i, buf.String(), test.expected)
-		}
+		assert.Equalf(t, test.expected, buf.String(), "#%d:\n got: %q\nwant: %q", i, buf.String(), test.expected)
 		buf.Reset()
 	}
 }
@@ -71,10 +71,7 @@ func TestHeaderSetGet(t *testing.T) {
 	}
 	h.Add("Other", "Value")
 	value := h.Get("Other")
-	if value != "Value" {
-		t.Errorf("got: %s, want: %s\n", value, "Value")
-	}
-
+	assert.Equalf(t, "Value", value, "got: %s, want: %s\n", value, "Value")
 }
 
 func TestHeaderClone(t *testing.T) {
@@ -86,9 +83,7 @@ func TestHeaderClone(t *testing.T) {
 
 	value := clone.Get("Custom")
 
-	if value != "Value" {
-		t.Errorf("got: %s, want: %s\n", value, "Value")
-	}
+	assert.Equalf(t, "Value", value, "got: %s, want: %s\n", value, "Value")
 
 }
 
diff --git a/ftwhttp/request_test.go b/ftwhttp/request_test.go
index afd4a57..2f02d69 100644
--- a/ftwhttp/request_test.go
+++ b/ftwhttp/request_test.go
@@ -1,9 +1,10 @@
 package ftwhttp
 
 import (
-	"bytes"
-	"strings"
+	"errors"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func generateBaseRequestForTesting() *Request {
@@ -44,9 +45,7 @@ Some-file-test-here
 ----------397236876--`)
 	req = NewRequest(rl, h, data, true)
 
-	if req.isRaw() {
-		t.Error()
-	}
+	assert.False(t, req.isRaw())
 }
 
 func generateBaseRawRequestForTesting() *Request {
@@ -76,9 +75,7 @@ User-Agent: ModSecurity CRS 3 Tests
 `)
 	req = NewRawRequest(raw, false)
 
-	if req.autoCompleteHeaders {
-		t.Fatalf("asdasd")
-	}
+	assert.False(t, req.autoCompleteHeaders)
 }
 func TestRequestLine(t *testing.T) {
 	rl := &RequestLine{
@@ -89,9 +86,7 @@ func TestRequestLine(t *testing.T) {
 
 	s := rl.ToString()
 
-	if s != "UNEXISTENT /this/path 1.4\r\n" {
-		t.Fatalf("Failed!")
-	}
+	assert.Equal(t, "UNEXISTENT /this/path 1.4\r\n", s)
 }
 
 func TestDestination(t *testing.T) {
@@ -101,26 +96,17 @@ func TestDestination(t *testing.T) {
 		Protocol: "https",
 	}
 
-	if d.DestAddr == "192.168.1.1" && d.Port == 443 && d.Protocol == "https" {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.Equal(t, "192.168.1.1", d.DestAddr)
+	assert.Equal(t, 443, d.Port)
+	assert.Equal(t, "https", d.Protocol)
 }
 
 func TestRequestNew(t *testing.T) {
 	req := generateBaseRequestForTesting()
 
 	head := req.Headers()
-	if head.Get("This") == "Header" {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
-
-	if !bytes.Equal(req.Data(), []byte("Data")) {
-		t.Error("Failed to set data")
-	}
+	assert.Equal(t, "Header", head.Get("This"))
+	assert.Equal(t, []byte("Data"), req.Data(), "Failed to set data")
 }
 
 func TestWithAutocompleteRequest(t *testing.T) {
@@ -137,9 +123,7 @@ func TestWithAutocompleteRequest(t *testing.T) {
 	data := []byte(`test=me&one=two`)
 	req = NewRequest(rl, h, data, true)
 
-	if !req.WithAutoCompleteHeaders() {
-		t.Error("Set Autocomplete headers error ")
-	}
+	assert.True(t, req.WithAutoCompleteHeaders(), "Set Autocomplete headers error ")
 }
 
 func TestWithoutAutocompleteRequest(t *testing.T) {
@@ -156,9 +140,7 @@ func TestWithoutAutocompleteRequest(t *testing.T) {
 	data := []byte(`test=me&one=two`)
 	req = NewRequest(rl, h, data, false)
 
-	if req.WithAutoCompleteHeaders() {
-		t.Error("Set Autocomplete headers error ")
-	}
+	assert.False(t, req.WithAutoCompleteHeaders(), "Set Autocomplete headers error ")
 }
 
 func TestRequestHeadersSet(t *testing.T) {
@@ -174,13 +156,10 @@ func TestRequestHeadersSet(t *testing.T) {
 	}
 
 	req.AddHeader("X-New-Header2", "Value")
-
-	if req.headers.Get("X-New-Header2") != "Value" {
-		t.Errorf("Failed !")
-	}
+	head := req.Headers()
+	assert.Equal(t, "Value", head.Get("X-New-Header2"))
 
 	req.AddStandardHeaders(5)
-
 }
 
 func TestRequestAutoCompleteHeaders(t *testing.T) {
@@ -188,11 +167,7 @@ func TestRequestAutoCompleteHeaders(t *testing.T) {
 
 	req.SetAutoCompleteHeaders(true)
 
-	if req.WithAutoCompleteHeaders() == true {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.True(t, req.WithAutoCompleteHeaders(), "Set Autocomplete headers error ")
 }
 
 func TestRequestData(t *testing.T) {
@@ -200,9 +175,8 @@ func TestRequestData(t *testing.T) {
 
 	err := req.SetData([]byte("This is the data now"))
 
-	if err != nil && !bytes.Equal(req.Data(), []byte("This is the data now")) {
-		t.Errorf("Failed !")
-	}
+	assert.NoError(t, err)
+	assert.Equal(t, []byte("This is the data now"), req.Data(), "failed to set data")
 }
 
 func TestRequestSettingRawDataWhenThereIsData(t *testing.T) {
@@ -210,37 +184,27 @@ func TestRequestSettingRawDataWhenThereIsData(t *testing.T) {
 
 	err := req.SetRawData([]byte("This is the data now"))
 
-	if err != nil && strings.Contains(err.Error(), "data field is already present in this request") {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed %s !", err.Error())
-	}
+	expectedError := errors.New("ftw/http: data field is already present in this request")
+	assert.Error(t, err)
+	assert.Equal(t, expectedError, err)
 }
 
 func TestRequestRawData(t *testing.T) {
 	req := generateBaseRawRequestForTesting()
 
-	if err := req.SetRawData([]byte("This is the RAW data now")); err != nil {
-		t.Errorf("Failed !")
-	}
+	err := req.SetRawData([]byte("This is the RAW data now"))
+	assert.NoError(t, err)
 
-	if bytes.Equal(req.RawData(), []byte("This is the RAW data now")) {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.Equal(t, []byte("This is the RAW data now"), req.RawData())
 }
 
 func TestRequestSettingDataaWhenThereIsRawData(t *testing.T) {
 	req := generateBaseRawRequestForTesting()
 
 	err := req.SetData([]byte("This is the data now"))
-
-	if err != nil && strings.Contains(err.Error(), "raw field is already present in this request") {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	expectedError := errors.New("ftw/http: raw field is already present in this request")
+	assert.Error(t, err)
+	assert.Equal(t, expectedError, err)
 }
 
 func TestRequestURLParse(t *testing.T) {
@@ -250,9 +214,7 @@ func TestRequestURLParse(t *testing.T) {
 	h.Add(ContentTypeHeader, "application/x-www-form-urlencoded")
 	// Test adding semicolons to test parse
 	err := req.SetData([]byte("test=This&test=nothing"))
-	if err != nil {
-		t.Errorf("Failed !")
-	}
+	assert.NoError(t, err)
 }
 
 func TestRequestURLParseFail(t *testing.T) {
@@ -262,7 +224,5 @@ func TestRequestURLParseFail(t *testing.T) {
 	h.Add(ContentTypeHeader, "application/x-www-form-urlencoded")
 	// Test adding semicolons to test parse
 	err := req.SetData([]byte("test=This&that=but with;;;;;; data now"))
-	if err != nil {
-		t.Errorf("Failed !")
-	}
+	assert.NoError(t, err)
 }
diff --git a/ftwhttp/response_test.go b/ftwhttp/response_test.go
index 56b8ce2..1503a46 100644
--- a/ftwhttp/response_test.go
+++ b/ftwhttp/response_test.go
@@ -6,6 +6,8 @@ import (
 	"net/http/httptest"
 	"testing"
 	"time"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func generateRequestForTesting(keepalive bool) *Request {
@@ -82,29 +84,18 @@ func TestResponse(t *testing.T) {
 	defer server.Close()
 
 	d, err := DestinationFromString(server.URL)
+	assert.NoError(t, err)
 
-	if err != nil {
-		t.Error(err)
-	}
 	req := generateRequestForTesting(true)
 
 	client := NewClient(NewClientConfig())
 	err = client.NewConnection(*d)
-
-	if err != nil {
-		t.Fatalf("Error! %s", err.Error())
-	}
+	assert.NoError(t, err)
 
 	response, err := client.Do(*req)
+	assert.NoError(t, err)
 
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if response.GetBodyAsString() != "Hello, client\n" {
-		t.Errorf("Error!")
-	}
-
+	assert.Equal(t, "Hello, client\n", response.GetBodyAsString())
 }
 
 func TestResponseWithCookies(t *testing.T) {
@@ -113,33 +104,23 @@ func TestResponseWithCookies(t *testing.T) {
 	defer server.Close()
 
 	d, err := DestinationFromString(server.URL)
-	if err != nil {
-		t.Fatalf("Error! %s", err.Error())
-	}
+	assert.NoError(t, err)
 	req := generateRequestForTesting(true)
 
 	client := NewClient(NewClientConfig())
 	err = client.NewConnection(*d)
 
-	if err != nil {
-		t.Fatalf("Error! %s", err.Error())
-	}
+	assert.NoError(t, err)
 
 	response, err := client.Do(*req)
 
-	if err != nil {
-		t.Logf("Failed !")
-	}
+	assert.NoError(t, err)
 
-	if response.GetBodyAsString() != "Setting Cookies!\n" {
-		t.Errorf("Error!")
-	}
+	assert.Equal(t, "Setting Cookies!\n", response.GetBodyAsString())
 
 	cookiereq := generateRequestWithCookiesForTesting()
 
 	_, err = client.Do(*cookiereq)
 
-	if err != nil {
-		t.Logf("Failed !")
-	}
+	assert.NoError(t, err)
 }
diff --git a/runner/run_test.go b/runner/run_test.go
index 1432d82..cf92d3d 100644
--- a/runner/run_test.go
+++ b/runner/run_test.go
@@ -8,6 +8,8 @@ import (
 	"regexp"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/rs/zerolog/log"
 
 	"github.com/coreruleset/go-ftw/check"
@@ -52,6 +54,17 @@ testoverride:
     this_does_not_exist: "test"
 `
 
+var yamlConfigIgnoreTests = `
+---
+testoverride:
+  ignore:
+    "001": "This test result must be ignored"
+  forcefail:
+    "008": "This test should pass, but it is going to fail"
+  forcepass:
+    "099": "This test failed, but it shall pass!"
+`
+
 var yamlCloudConfig = `
 ---
 mode: cloud
@@ -77,7 +90,7 @@ tests:
       - stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
               User-Agent: "ModSecurity CRS 3 Tests"
@@ -87,11 +100,12 @@ tests:
             expect_error: False
             status: [200]
   - test_title: "008"
+    description: "this test is number 8"
     stages:
       - stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
               User-Agent: "ModSecurity CRS 3 Tests"
@@ -104,7 +118,7 @@ tests:
       - stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             version: "HTTP/1.1"
             method: "OTHER"
@@ -159,7 +173,7 @@ tests:
         stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
                 User-Agent: "ModSecurity CRS 3 Tests"
@@ -209,7 +223,7 @@ tests:
         stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
                 User-Agent: "ModSecurity CRS 3 Tests"
@@ -230,7 +244,7 @@ tests:
       - stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
               User-Agent: "ModSecurity CRS 3 Tests"
@@ -243,7 +257,7 @@ tests:
       - stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
               User-Agent: "ModSecurity CRS 3 Tests"
@@ -266,7 +280,7 @@ tests:
       - stage:
           input:
             dest_addr: "TEST_ADDR"
-	    # -1 designates port value must be replaced by test setup
+            # -1 designates port value must be replaced by test setup
             port: -1
             headers:
               User-Agent: "ModSecurity CRS 3 Tests"
@@ -292,8 +306,7 @@ func newTestServer(t *testing.T, logLines string) (destination *ftwhttp.Destinat
 
 	dest, err := ftwhttp.DestinationFromString(ts.URL)
 	if err != nil {
-		t.Error(err)
-		t.FailNow()
+		assert.FailNow(t, "cannot get destination from string", err.Error())
 	}
 	return dest, logFilePath
 }
@@ -310,9 +323,9 @@ func newTestServerForCloudTest(t *testing.T, responseStatus int, logLines string
 
 	dest, err := ftwhttp.DestinationFromString(server.URL)
 	if err != nil {
-		t.Error(err)
-		t.FailNow()
+		assert.FailNow(t, "cannot get destination from string", err.Error())
 	}
+
 	return server, dest
 }
 
@@ -324,9 +337,7 @@ func setUpLogFileForTestServer(t *testing.T) (logFilePath string) {
 	// if no file has been configured, create one and handle cleanup
 	if logFilePath == "" {
 		file, err := os.CreateTemp("", "go-ftw-test-*.log")
-		if err != nil {
-			t.Error(err)
-		}
+		assert.NoError(t, err)
 		logFilePath = file.Name()
 		t.Cleanup(func() {
 			os.Remove(logFilePath)
@@ -346,15 +357,13 @@ func writeTestServerLog(t *testing.T, logLines string, logFilePath string, r *ht
 	}
 	file, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
 	if err != nil {
-		t.Error(err)
-		t.FailNow()
+		assert.FailNow(t, "cannot open file", err.Error())
 	}
 	defer file.Close()
 
 	_, err = file.WriteString(logMessage)
 	if err != nil {
-		t.Error(err)
-		t.FailNow()
+		assert.FailNow(t, "cannot write log message to file", err.Error())
 	}
 }
 
@@ -397,70 +406,61 @@ func TestRun(t *testing.T) {
 	t.Cleanup(config.Reset)
 
 	err := config.NewConfigFromString(yamlConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	// setup test webserver (not a waf)
 	dest, logFilePath := newTestServer(t, logText)
 	config.FTWConfig.LogFile = logFilePath
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlTest))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
+
 	replaceDestinationInTest(&ftwTest, *dest)
 
 	t.Run("show time and execute all", func(t *testing.T) {
-		if res := Run([]test.FTWTest{ftwTest}, Config{
+		res := Run([]test.FTWTest{ftwTest}, Config{
 			ShowTime: true,
 			Quiet:    true,
-		}); res.Stats.TotalFailed() > 0 {
-			t.Errorf("Oops, %d tests failed to run!", res.Stats.TotalFailed())
-		}
+		})
+		assert.Equalf(t, res.Stats.TotalFailed(), 0, "Oops, %d tests failed to run!", res.Stats.TotalFailed())
 	})
 
 	t.Run("be verbose and execute all", func(t *testing.T) {
-		if res := Run([]test.FTWTest{ftwTest}, Config{
+		res := Run([]test.FTWTest{ftwTest}, Config{
 			Include:  regexp.MustCompile("0*"),
 			ShowTime: true,
-		}); res.Stats.TotalFailed() > 0 {
-			t.Error("Oops, test run failed!")
-		}
+		})
+		assert.Equal(t, res.Stats.TotalFailed(), 0, "verbose and execute all failed")
 	})
 
 	t.Run("don't show time and execute all", func(t *testing.T) {
-		if res := Run([]test.FTWTest{ftwTest}, Config{
+		res := Run([]test.FTWTest{ftwTest}, Config{
 			Include: regexp.MustCompile("0*"),
-		}); res.Stats.TotalFailed() > 0 {
-			t.Error("Oops, test run failed!")
-		}
+		})
+		assert.Equal(t, res.Stats.TotalFailed(), 0, "do not show time and execute all failed")
 	})
 
 	t.Run("execute only test 008 but exclude all", func(t *testing.T) {
-		if res := Run([]test.FTWTest{ftwTest}, Config{
+		res := Run([]test.FTWTest{ftwTest}, Config{
 			Include: regexp.MustCompile("008"),
 			Exclude: regexp.MustCompile("0*"),
-		}); res.Stats.TotalFailed() > 0 {
-			t.Error("Oops, test run failed!")
-		}
+		})
+		assert.Equal(t, res.Stats.TotalFailed(), 0, "do not show time and execute all failed")
 	})
 
 	t.Run("exclude test 010", func(t *testing.T) {
-		if res := Run([]test.FTWTest{ftwTest}, Config{
+		res := Run([]test.FTWTest{ftwTest}, Config{
 			Exclude: regexp.MustCompile("010"),
-		}); res.Stats.TotalFailed() > 0 {
-			t.Error("Oops, test run failed!")
-		}
+		})
+		assert.Equal(t, res.Stats.TotalFailed(), 0, "failed to exclude test")
 	})
 
 	t.Run("test exceptions 1", func(t *testing.T) {
-		if res := Run([]test.FTWTest{ftwTest}, Config{
+		res := Run([]test.FTWTest{ftwTest}, Config{
 			Include: regexp.MustCompile("1*"),
 			Exclude: regexp.MustCompile("0*"),
 			Quiet:   true,
-		}); res.Stats.TotalFailed() > 0 {
-			t.Error("Oops, test run failed!")
-		}
+		})
+		assert.Equal(t, res.Stats.TotalFailed(), 0, "failed to test exceptions")
 	})
 }
 
@@ -469,9 +469,7 @@ func TestOverrideRun(t *testing.T) {
 
 	// setup test webserver (not a waf)
 	err := config.NewConfigFromString(yamlConfigOverride)
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 
 	dest, logFilePath := newTestServer(t, logText)
 
@@ -481,29 +479,25 @@ func TestOverrideRun(t *testing.T) {
 	// replace host and port with values that can be overridden by config
 	fakeDestination, err := ftwhttp.DestinationFromString("http://example.com:1234")
 	if err != nil {
-		t.Fatalf("Failed to parse fake destination")
+		assert.FailNow(t, err.Error(), "Failed to parse fake destination")
 	}
 
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlTestOverride))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
+
 	replaceDestinationInTest(&ftwTest, *fakeDestination)
 
-	if res := Run([]test.FTWTest{ftwTest}, Config{
+	res := Run([]test.FTWTest{ftwTest}, Config{
 		Quiet: true,
-	}); res.Stats.TotalFailed() > 0 {
-		t.Error("Oops, test run failed!")
-	}
+	})
+	assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!")
 }
 
 func TestBrokenOverrideRun(t *testing.T) {
 	t.Cleanup(config.Reset)
 
 	err := config.NewConfigFromString(yamlBrokenConfigOverride)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	dest, logFilePath := newTestServer(t, logText)
 
@@ -513,21 +507,19 @@ func TestBrokenOverrideRun(t *testing.T) {
 	// replace host and port with values that can be overridden by config
 	fakeDestination, err := ftwhttp.DestinationFromString("http://example.com:1234")
 	if err != nil {
-		t.Fatalf("Failed to parse fake destination")
+		assert.FailNow(t, err.Error(), "Failed to parse fake destination")
 	}
 
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlTestOverride))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
+
 	replaceDestinationInTest(&ftwTest, *fakeDestination)
 
 	// the test should succeed, despite the unknown override property
-	if res := Run([]test.FTWTest{ftwTest}, Config{
+	res := Run([]test.FTWTest{ftwTest}, Config{
 		Quiet: true,
-	}); res.Stats.TotalFailed() > 0 {
-		t.Error("Oops, test run failed!")
-	}
+	})
+	assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!")
 }
 
 func TestBrokenPortOverrideRun(t *testing.T) {
@@ -538,9 +530,7 @@ func TestBrokenPortOverrideRun(t *testing.T) {
 
 	// replace destination port inside the yaml with the retrieved one
 	err := config.NewConfigFromString(fmt.Sprintf(yamlConfigPortOverride, dest.Port))
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	replaceDestinationInConfiguration(*dest)
 	config.FTWConfig.LogFile = logFilePath
@@ -548,47 +538,40 @@ func TestBrokenPortOverrideRun(t *testing.T) {
 	// replace host and port with values that can be overridden by config
 	fakeDestination, err := ftwhttp.DestinationFromString("http://example.com:1234")
 	if err != nil {
-		t.Fatalf("Failed to parse fake destination")
+		assert.FailNow(t, err.Error(), "Failed to parse fake destination")
 	}
 
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlTestOverrideWithNoPort))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
+
 	replaceDestinationInTest(&ftwTest, *fakeDestination)
 
 	// the test should succeed, despite the unknown override property
-	if res := Run([]test.FTWTest{ftwTest}, Config{
+	res := Run([]test.FTWTest{ftwTest}, Config{
 		Quiet: true,
-	}); res.Stats.TotalFailed() > 0 {
-		t.Error("Oops, test run failed!")
-	}
+	})
+	assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!")
 }
 
 func TestDisabledRun(t *testing.T) {
 	t.Cleanup(config.Reset)
 
 	err := config.NewConfigFromString(yamlConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	fakeDestination, err := ftwhttp.DestinationFromString("http://example.com:1234")
 	if err != nil {
-		t.Fatalf("Failed to parse fake destination")
+		assert.FailNow(t, err.Error(), "Failed to parse fake destination")
 	}
 
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlDisabledTest))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 	replaceDestinationInTest(&ftwTest, *fakeDestination)
 
-	if res := Run([]test.FTWTest{ftwTest}, Config{
+	res := Run([]test.FTWTest{ftwTest}, Config{
 		Quiet: true,
-	}); res.Stats.TotalFailed() > 0 {
-		t.Error("Oops, test run failed!")
-	}
+	})
+	assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!")
 }
 
 func TestLogsRun(t *testing.T) {
@@ -598,37 +581,28 @@ func TestLogsRun(t *testing.T) {
 	dest, logFilePath := newTestServer(t, logText)
 
 	err := config.NewConfigFromString(yamlConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 	replaceDestinationInConfiguration(*dest)
 	config.FTWConfig.LogFile = logFilePath
 
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlTestLogs))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 	replaceDestinationInTest(&ftwTest, *dest)
 
-	if res := Run([]test.FTWTest{ftwTest}, Config{
+	res := Run([]test.FTWTest{ftwTest}, Config{
 		Quiet: true,
-	}); res.Stats.TotalFailed() > 0 {
-		t.Error("Oops, test run failed!")
-	}
+	})
+	assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!")
 }
 
 func TestCloudRun(t *testing.T) {
 	t.Cleanup(config.Reset)
 
 	err := config.NewConfigFromString(yamlCloudConfig)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+	assert.NoError(t, err)
 
 	ftwTestDummy, err := test.GetTestFromYaml([]byte(yamlTestLogs))
-	if err != nil {
-		t.Error(err)
-	}
+	assert.NoError(t, err)
 
 	t.Run("don't show time and execute all", func(t *testing.T) {
 		for testCaseIndex, testCaseDummy := range ftwTestDummy.Tests {
@@ -637,9 +611,7 @@ func TestCloudRun(t *testing.T) {
 				// in each run. The server needs to be configured for each stage
 				// individually.
 				ftwTest, err := test.GetTestFromYaml([]byte(yamlTestLogs))
-				if err != nil {
-					t.Error(err)
-				}
+				assert.NoError(t, err)
 				testCase := &ftwTest.Tests[testCaseIndex]
 				stage := &testCase.Stages[stageIndex].Stage
 
@@ -657,9 +629,7 @@ func TestCloudRun(t *testing.T) {
 				replaceDestinationInConfiguration(*dest)
 
 				replaceDestinationInTest(&ftwTest, *dest)
-				if err != nil {
-					t.Error(err)
-				}
+				assert.NoError(t, err)
 				runContext := TestRunContext{
 					Include:  nil,
 					Exclude:  nil,
@@ -670,9 +640,7 @@ func TestCloudRun(t *testing.T) {
 				}
 
 				RunStage(&runContext, ftwCheck, *testCase, *stage)
-				if runContext.Stats.TotalFailed() > 0 {
-					t.Error("Oops, test run failed!")
-				}
+				assert.LessOrEqual(t, 0, runContext.Stats.TotalFailed(), "Oops, test run failed!")
 
 				server.Close()
 			}
@@ -684,22 +652,18 @@ func TestFailedTestsRun(t *testing.T) {
 	t.Cleanup(config.Reset)
 
 	err := config.NewConfigFromString(yamlConfig)
+	assert.NoError(t, err)
 	dest, logFilePath := newTestServer(t, logText)
-	if err != nil {
-		t.Errorf("Failed!")
-	}
+
 	replaceDestinationInConfiguration(*dest)
 	config.FTWConfig.LogFile = logFilePath
 
 	ftwTest, err := test.GetTestFromYaml([]byte(yamlFailedTest))
-	if err != nil {
-		t.Error(err.Error())
-	}
+	assert.NoError(t, err)
 	replaceDestinationInTest(&ftwTest, *dest)
 
-	if res := Run([]test.FTWTest{ftwTest}, Config{}); res.Stats.TotalFailed() != 1 {
-		t.Error("Oops, test run failed!")
-	}
+	res := Run([]test.FTWTest{ftwTest}, Config{})
+	assert.Equal(t, 1, res.Stats.TotalFailed())
 }
 
 func TestApplyInputOverrideSetHostFromDestAddr(t *testing.T) {
@@ -719,22 +683,32 @@ func TestApplyInputOverrideSetHostFromDestAddr(t *testing.T) {
 	}
 
 	err := applyInputOverride(&testInput)
-	if err != nil {
-		t.Error("Failed to apply input overrides", err)
-	}
+	assert.NoError(t, err, "Failed to apply input overrides")
 
-	if *testInput.DestAddr != overrideHost {
-		t.Error("`dest_addr` should have been overridden")
-	}
-	if testInput.Headers == nil {
-		t.Error("Header map must exist after overriding `dest_addr`")
-	}
+	assert.Equal(t, overrideHost, *testInput.DestAddr, "`dest_addr` should have been overridden")
+
+	assert.NotNil(t, testInput.Headers, "Header map must exist after overriding `dest_addr`")
 
 	hostHeader := testInput.Headers.Get("Host")
-	if hostHeader == "" {
-		t.Error("Host header must be set after overriding `dest_addr`")
-	}
-	if hostHeader != overrideHost {
-		t.Error("Host header must be identical to `dest_addr` after overrding `dest_addr`")
-	}
+	assert.NotEqual(t, "", hostHeader, "Host header must be set after overriding `dest_addr`")
+	assert.Equal(t, overrideHost, hostHeader, "Host header must be identical to `dest_addr` after overrding `dest_addr`")
+}
+
+func TestIgnoredTestsRun(t *testing.T) {
+	t.Cleanup(config.Reset)
+
+	err := config.NewConfigFromString(yamlConfigIgnoreTests)
+	dest, logFilePath := newTestServer(t, logText)
+	assert.NoError(t, err)
+
+	replaceDestinationInConfiguration(*dest)
+	config.FTWConfig.LogFile = logFilePath
+
+	ftwTest, err := test.GetTestFromYaml([]byte(yamlTest))
+	assert.NoError(t, err)
+
+	replaceDestinationInTest(&ftwTest, *dest)
+
+	res := Run([]test.FTWTest{ftwTest}, Config{})
+	assert.Equal(t, res.Stats.TotalFailed(), 1, "Oops, test run failed!")
 }
diff --git a/test/data_test.go b/test/data_test.go
index cb6e487..7c60129 100644
--- a/test/data_test.go
+++ b/test/data_test.go
@@ -1,9 +1,10 @@
 package test
 
 import (
-	"bytes"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/goccy/go-yaml"
 )
 
@@ -25,12 +26,8 @@ uri: "/"
 `
 	input := Input{}
 	err := yaml.Unmarshal([]byte(yamlString), &input)
-
-	if err == nil && input.StopMagic == true {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.NoError(t, err)
+	assert.True(t, input.StopMagic)
 }
 
 func TestGetPartialDataFromYAML(t *testing.T) {
@@ -50,12 +47,8 @@ uri: "/"
 `
 	input := Input{}
 	err := yaml.Unmarshal([]byte(yamlString), &input)
-
-	if err == nil && *input.Version == "" {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.NoError(t, err)
+	assert.Empty(t, *input.Version)
 }
 
 func TestDataTemplateFromYAML(t *testing.T) {
@@ -77,13 +70,7 @@ uri: "/"
 	var data []byte
 	err := yaml.Unmarshal([]byte(yamlString), &input)
 
-	if err != nil {
-		t.Fatalf("Failed !")
-	}
-
-	if data = input.ParseData(); bytes.Equal(data, []byte(repeatTestSprig)) {
-		t.Logf("Success !")
-	} else {
-		t.Fatalf("Failed: %s", data)
-	}
+	assert.NoError(t, err)
+	data = input.ParseData()
+	assert.Equal(t, []byte(repeatTestSprig), data)
 }
diff --git a/test/defaults_test.go b/test/defaults_test.go
index 25a618e..2598375 100644
--- a/test/defaults_test.go
+++ b/test/defaults_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/coreruleset/go-ftw/ftwhttp"
+	"github.com/stretchr/testify/assert"
 )
 
 func getTestInputDefaults() *Input {
@@ -75,75 +76,51 @@ User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0
 func TestBasicGetters(t *testing.T) {
 	input := getTestExampleInput()
 
-	if dest := input.GetDestAddr(); dest != "192.168.0.1" {
-		t.Fatalf("Error!")
-	}
-
-	if method := input.GetMethod(); method != "REPORT" {
-		t.Fatalf("Error!")
-	}
-
-	if version := input.GetVersion(); version != "HTTP/1.1" {
-		t.Fatalf("Error!")
-	}
-
-	if port := input.GetPort(); port != 8080 {
-		t.Fatalf("Error!")
-	}
-
-	if val := input.GetProtocol(); val != "http" {
-		t.Fatalf("Error!")
-	}
-
-	if val := input.GetURI(); val != "/test" {
-		t.Fatalf("Error!")
-	}
-
-	if request, _ := input.GetRawRequest(); !bytes.Equal(request, []byte("My Data\n")) {
-		t.Fatalf("Error!")
-	}
+	dest := input.GetDestAddr()
+	assert.Equal(t, "192.168.0.1", dest)
+	method := input.GetMethod()
+	assert.Equal(t, "REPORT", method)
+	version := input.GetVersion()
+	assert.Equal(t, "HTTP/1.1", version)
+	port := input.GetPort()
+	assert.Equal(t, 8080, port)
+	proto := input.GetProtocol()
+	assert.Equal(t, "http", proto)
+	uri := input.GetURI()
+	assert.Equal(t, "/test", uri)
+	request, _ := input.GetRawRequest()
+	assert.Equal(t, []byte("My Data\n"), request)
 }
 
 func TestDefaultGetters(t *testing.T) {
 	inputDefaults := getTestInputDefaults()
 
-	if val := inputDefaults.GetDestAddr(); val != "localhost" {
-		t.Fatalf("Error!")
-	}
+	val := inputDefaults.GetDestAddr()
+	assert.Equal(t, "localhost", val)
 
-	if val := inputDefaults.GetMethod(); val != "GET" {
-		t.Fatalf("Error!")
-	}
+	val = inputDefaults.GetMethod()
+	assert.Equal(t, "GET", val)
 
-	if val := inputDefaults.GetVersion(); val != "HTTP/1.1" {
-		t.Fatalf("Error!")
-	}
+	val = inputDefaults.GetVersion()
+	assert.Equal(t, "HTTP/1.1", val)
 
-	if val := inputDefaults.GetPort(); val != 80 {
-		t.Fatalf("Error!")
-	}
+	port := inputDefaults.GetPort()
+	assert.Equal(t, 80, port)
 
-	if val := inputDefaults.GetProtocol(); val != "http" {
-		t.Fatalf("Error!")
-	}
+	val = inputDefaults.GetProtocol()
+	assert.Equal(t, "http", val)
 
-	if val := inputDefaults.GetURI(); val != "/" {
-		t.Fatalf("Error!")
-	}
+	val = inputDefaults.GetURI()
+	assert.Equal(t, "/", val)
 
-	if !bytes.Equal([]byte(*inputDefaults.Data), []byte("My Data")) {
-		t.Fatalf("Error!")
-	}
+	assert.Equal(t, []byte("My Data"), []byte(*inputDefaults.Data))
 }
 
 func TestRaw(t *testing.T) {
 	raw := getRawInput()
 
-	if raw.StopMagic != true {
-		t.Fatalf("Error!")
-	}
+	assert.True(t, raw.StopMagic)
 
-	if request, _ := raw.GetRawRequest(); bytes.Index(request, []byte("Acunetix")) == 2 {
-		t.Fatalf("Error!")
-	}
+	request, _ := raw.GetRawRequest()
+	assert.NotEqual(t, 2, bytes.Index(request, []byte("Acunetix")))
 }
diff --git a/test/errors_test.go b/test/errors_test.go
index 9701fb6..d2a5eed 100644
--- a/test/errors_test.go
+++ b/test/errors_test.go
@@ -3,6 +3,8 @@ package test
 import (
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/utils"
 )
 
@@ -48,8 +50,6 @@ func TestGetLinesFromTestName(t *testing.T) {
 
 	for _, ft := range tests {
 		line, _ := ft.GetLinesFromTest("911100-2")
-		if line != 22 {
-			t.Errorf("Not getting the proper line.")
-		}
+		assert.Equal(t, 22, line, "Not getting the proper line.")
 	}
 }
diff --git a/test/files_test.go b/test/files_test.go
index 20d5440..b192010 100644
--- a/test/files_test.go
+++ b/test/files_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/coreruleset/go-ftw/utils"
+	"github.com/stretchr/testify/assert"
 )
 
 var yamlTest = `
@@ -53,21 +54,14 @@ func TestGetTestFromYAML(t *testing.T) {
 	tests, _ := GetTestsFromFiles(filename)
 
 	for _, ft := range tests {
-		if ft.FileName != filename {
-			t.Fatalf("Error!")
-		}
-		if ft.Meta.Author != "tester" {
-			t.Fatalf("Error!")
-		}
-		if ft.Meta.Name != "911100.yaml" {
-			t.Fatalf("Error!")
-		}
+		assert.Equal(t, filename, ft.FileName)
+		assert.Equal(t, "tester", ft.Meta.Author)
+		assert.Equal(t, "911100.yaml", ft.Meta.Name)
+
 		re := regexp.MustCompile("911100*")
 
 		for _, test := range ft.Tests {
-			if ok := re.MatchString(test.TestTitle); !ok {
-				t.Fatalf("Can't read test title")
-			}
+			assert.True(t, re.MatchString(test.TestTitle), "Can't read test title")
 		}
 	}
 }
@@ -76,7 +70,5 @@ func TestGetFromBadYAML(t *testing.T) {
 	filename, _ := utils.CreateTempFileWithContent(wrongYamlTest, "test-yaml-*")
 	_, err := GetTestsFromFiles(filename)
 
-	if err == nil {
-		t.Fatalf("Error!")
-	}
+	assert.NotNil(t, err, "reading yaml should fail")
 }
diff --git a/utils/empty_test.go b/utils/empty_test.go
index b7e2b6b..5598449 100644
--- a/utils/empty_test.go
+++ b/utils/empty_test.go
@@ -2,84 +2,51 @@ package utils
 
 import (
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestIsEmpty(t *testing.T) {
 	data := ""
-
-	if IsEmpty(data) {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.True(t, IsEmpty(data))
 }
 
 func TestIsEmptyStringPointer(t *testing.T) {
 	var empty *string = nil
-
-	if !IsEmpty(empty) {
-		t.Errorf("Failed !")
-	}
+	assert.True(t, IsEmpty(empty))
 }
 
 func TestIsEmptyByte(t *testing.T) {
 	data := []byte{}
-
-	if IsEmpty(data) {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.True(t, IsEmpty(data))
 }
 
 func TestIsNotEmpty(t *testing.T) {
 	data := "Not Empty"
-
-	if IsNotEmpty(data) {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.True(t, IsNotEmpty(data))
 }
 
 func TestIsNotEmptyByte(t *testing.T) {
 	data := []byte("Not Empty")
-
-	if IsNotEmpty(data) {
-		t.Logf("Success !")
-	} else {
-		t.Errorf("Failed !")
-	}
+	assert.True(t, IsNotEmpty(data))
 }
 
 func TestStringPEmpty(t *testing.T) {
 	var s *string
-
-	if !IsEmpty(s) {
-		t.Errorf("Failed")
-	}
+	assert.True(t, IsEmpty(s))
 }
 
 func TestStringPNotEmpty(t *testing.T) {
 	s := string("Empty")
-
-	if !IsNotEmpty(&s) {
-		t.Errorf("Failed")
-	}
+	assert.True(t, IsNotEmpty(&s))
 }
 
 func TestAnythingNotEmpty(t *testing.T) {
 	data := make([]int, 1, 2)
-
-	if IsEmpty(data) {
-		t.Errorf("Failed !")
-	}
+	assert.False(t, IsEmpty(data))
 }
 
 func TestAnythingEmpty(t *testing.T) {
 	data := make([]int, 1, 2)
-
-	if IsNotEmpty(data) {
-		t.Errorf("Failed !")
-	}
+	assert.False(t, IsNotEmpty(data), "[]int is not implemented so it should return false")
 }
diff --git a/utils/tests_test.go b/utils/tests_test.go
index 1b16db4..8da2e35 100644
--- a/utils/tests_test.go
+++ b/utils/tests_test.go
@@ -3,6 +3,8 @@ package utils
 import (
 	"os"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 var content = `This is the content`
@@ -12,9 +14,7 @@ func TestCreateTempFile(t *testing.T) {
 	// Remember to clean up the file afterwards
 	defer os.Remove(filename)
 
-	if err != nil {
-		t.Fatalf("Error!")
-	}
+	assert.NoError(t, err)
 }
 
 func TestCreateBadTempFile(t *testing.T) {
@@ -22,7 +22,5 @@ func TestCreateBadTempFile(t *testing.T) {
 	// Remember to clean up the file afterwards
 	defer os.Remove(filename)
 
-	if err == nil {
-		t.Fatalf("Error!")
-	}
+	assert.NotNil(t, err)
 }
diff --git a/utils/time_test.go b/utils/time_test.go
index a56c349..9c0ae0a 100644
--- a/utils/time_test.go
+++ b/utils/time_test.go
@@ -2,12 +2,12 @@ package utils
 
 import (
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestGetFormattedTime(t *testing.T) {
 	ftm := GetFormattedTime("2021-01-05T00:30:26.371Z")
 
-	if ftm.Year() != 2021 {
-		t.Errorf("Error!")
-	}
+	assert.Equal(t, 2021, ftm.Year())
 }
diff --git a/waflog/read_test.go b/waflog/read_test.go
index 41d49c0..3a6657c 100644
--- a/waflog/read_test.go
+++ b/waflog/read_test.go
@@ -7,14 +7,15 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 	"github.com/coreruleset/go-ftw/utils"
 )
 
 func TestReadCheckLogForMarkerNoMarkerAtEnd(t *testing.T) {
-	if err := config.NewConfigFromEnv(); err != nil {
-		t.Error(err)
-	}
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
 
 	stageID := "dead-beaf-deadbeef-deadbeef-dead"
 	markerLine := "X-cRs-TeSt: " + stageID
@@ -25,24 +26,20 @@ func TestReadCheckLogForMarkerNoMarkerAtEnd(t *testing.T) {
 [Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]
 `
 	filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NoError(t, err)
+
 	config.FTWConfig.LogFile = filename
 	t.Cleanup(func() { os.Remove(filename) })
 
 	ll := NewFTWLogLines(WithStartMarker(bytes.ToLower([]byte(markerLine))))
 
 	marker := ll.CheckLogForMarker(stageID)
-	if marker != nil {
-		t.Fatal("unexpectedly found marker")
-	}
+	assert.Nil(t, marker, "unexpectedly found marker")
 }
 
 func TestReadCheckLogForMarkerWithMarkerAtEnd(t *testing.T) {
-	if err := config.NewConfigFromEnv(); err != nil {
-		t.Error(err)
-	}
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
 
 	stageID := "dead-beaf-deadbeef-deadbeef-dead"
 	markerLine := "X-cRs-TeSt: " + stageID
@@ -52,24 +49,23 @@ func TestReadCheckLogForMarkerWithMarkerAtEnd(t *testing.T) {
 [Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]
 ` + markerLine
 	filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NoError(t, err)
+
 	config.FTWConfig.LogFile = filename
 	t.Cleanup(func() { os.Remove(filename) })
 
 	ll := NewFTWLogLines(WithStartMarker(bytes.ToLower([]byte(markerLine))))
 
 	marker := ll.CheckLogForMarker(stageID)
-	if marker == nil {
-		t.Fatal("no marker found")
-	}
-	if !bytes.Equal(marker, bytes.ToLower([]byte(markerLine))) {
-		t.Fatal("found unexpected marker")
-	}
+	assert.NotNil(t, marker, "no marker found")
+
+	assert.Equal(t, marker, bytes.ToLower([]byte(markerLine)), "found unexpected marker")
 }
 
 func TestReadGetMarkedLines(t *testing.T) {
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
+
 	stageID := "dead-beaf-deadbeef-deadbeef-dead"
 	startMarkerLine := "X-cRs-TeSt: " + stageID + " -start"
 	endMarkerLine := "X-cRs-TeSt: " + stageID + " -end"
@@ -79,9 +75,8 @@ func TestReadGetMarkedLines(t *testing.T) {
 [Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]`
 	logLines := fmt.Sprintf("%s\n%s\n%s", startMarkerLine, logLinesOnly, endMarkerLine)
 	filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NoError(t, err)
+
 	config.FTWConfig.LogFile = filename
 	t.Cleanup(func() { os.Remove(filename) })
 
@@ -96,17 +91,17 @@ func TestReadGetMarkedLines(t *testing.T) {
 		foundLines[i], foundLines[j] = foundLines[j], foundLines[i]
 	}
 
-	if len(foundLines) != 3 {
-		t.Fatal("found unexpected number of log lines")
-	}
+	assert.Equal(t, len(foundLines), 3, "found unexpected number of log lines")
+
 	for index, line := range strings.Split(logLinesOnly, "\n") {
-		if !bytes.Equal(foundLines[index], []byte(line)) {
-			t.Fatalf("log lines don't match: \n%s\n%s", line, string(foundLines[index]))
-		}
+		assert.Equalf(t, foundLines[index], []byte(line), "log lines don't match: \n%s\n%s", line, string(foundLines[index]))
 	}
 }
 
 func TestReadGetMarkedLinesWithTrailingEmptyLines(t *testing.T) {
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
+
 	stageID := "dead-beaf-deadbeef-deadbeef-dead"
 	startMarkerLine := "X-cRs-TeSt: " + stageID + " -start"
 	endMarkerLine := "X-cRs-TeSt: " + stageID + " -end"
@@ -116,9 +111,8 @@ func TestReadGetMarkedLinesWithTrailingEmptyLines(t *testing.T) {
 [Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]`
 	logLines := fmt.Sprintf("%s\n%s\n%s\n\n\n", startMarkerLine, logLinesOnly, endMarkerLine)
 	filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NoError(t, err)
+
 	config.FTWConfig.LogFile = filename
 	t.Cleanup(func() { os.Remove(filename) })
 
@@ -133,17 +127,17 @@ func TestReadGetMarkedLinesWithTrailingEmptyLines(t *testing.T) {
 		foundLines[i], foundLines[j] = foundLines[j], foundLines[i]
 	}
 
-	if len(foundLines) != 6 {
-		t.Fatal("found unexpected number of log lines")
-	}
+	assert.Len(t, foundLines, 6, "found unexpected number of log lines")
+
 	for index, line := range strings.Split(logLinesOnly, "\n") {
-		if !bytes.Equal(foundLines[index], []byte(line)) {
-			t.Fatalf("log lines don't match: \n%s\n%s", line, string(foundLines[index]))
-		}
+		assert.Equalf(t, foundLines[index], []byte(line), "log lines don't match: \n%s\n%s", line, string(foundLines[index]))
 	}
 }
 
 func TestReadGetMarkedLinesWithPrecedingLines(t *testing.T) {
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
+
 	stageID := "dead-beaf-deadbeef-deadbeef-dead"
 	startMarkerLine := "X-cRs-TeSt: " + stageID + " -start"
 	endMarkerLine := "X-cRs-TeSt: " + stageID + " -end"
@@ -156,9 +150,8 @@ func TestReadGetMarkedLinesWithPrecedingLines(t *testing.T) {
 [Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]`
 	logLines := fmt.Sprintf("%s\n%s\n%s\n%s\n", precedingLines, startMarkerLine, logLinesOnly, endMarkerLine)
 	filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NoError(t, err)
+
 	config.FTWConfig.LogFile = filename
 	t.Cleanup(func() { os.Remove(filename) })
 
@@ -173,12 +166,82 @@ func TestReadGetMarkedLinesWithPrecedingLines(t *testing.T) {
 		foundLines[i], foundLines[j] = foundLines[j], foundLines[i]
 	}
 
-	if len(foundLines) != 4 {
-		t.Fatal("found unexpected number of log lines")
-	}
+	assert.Len(t, foundLines, 4, "found unexpected number of log lines")
+
 	for index, line := range strings.Split(logLinesOnly, "\n") {
-		if !bytes.Equal(foundLines[index], []byte(line)) {
-			t.Fatalf("log lines don't match: \n%s\n%s", line, string(foundLines[index]))
-		}
+		assert.Equalf(t, foundLines[index], []byte(line), "log lines don't match: \n%s\n%s", line, string(foundLines[index]))
+	}
+}
+
+func TestFTWLogLines_Contains(t *testing.T) {
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
+
+	stageID := "dead-beaf-deadbeef-deadbeef-dead"
+	markerLine := "X-cRs-TeSt: " + stageID
+	logLines := `
+[Tue Jan 05 02:21:09.637165 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Pattern match "\\\\b(?:keep-alive|close),\\\\s?(?:keep-alive|close)\\\\b" at REQUEST_HEADERS:Connection. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "339"] [id "920210"] [msg "Multiple/Conflicting Connection Header Data Found"] [data "close,close"] [severity "WARNING"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/210/272"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]
+[Tue Jan 05 02:21:09.637731 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Match of "pm AppleWebKit Android" against "REQUEST_HEADERS:User-Agent" required. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "1230"] [id "920300"] [msg "Request Missing an Accept Header"] [severity "NOTICE"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS"] [tag "capec/1000/210/272"] [tag "PCI/6.5.10"] [tag "paranoia-level/2"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]
+[Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]
+` + markerLine
+	filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-")
+	assert.NoError(t, err)
+
+	config.FTWConfig.LogFile = filename
+	log, err := os.Open(filename)
+	assert.NoError(t, err)
+
+	t.Cleanup(func() { os.Remove(filename) })
+
+	type fields struct {
+		logFile     *os.File
+		FileName    string
+		StartMarker []byte
+		EndMarker   []byte
+	}
+	f := fields{
+		logFile:     log,
+		FileName:    filename,
+		StartMarker: []byte(markerLine),
+		EndMarker:   []byte(markerLine),
+	}
+
+	type args struct {
+		match string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   bool
+	}{
+		{
+			name:   "Test contains element",
+			fields: f,
+			args: args{
+				match: "AppleWebKit",
+			},
+			want: true,
+		},
+		{
+			name:   "Test does not contain element",
+			fields: f,
+			args: args{
+				match: "Something that does not exist",
+			},
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ll := &FTWLogLines{
+				logFile:     tt.fields.logFile,
+				FileName:    tt.fields.FileName,
+				StartMarker: tt.fields.StartMarker,
+				EndMarker:   tt.fields.EndMarker,
+			}
+			got := ll.Contains(tt.args.match)
+			assert.Equalf(t, tt.want, got, "Contains() = %v, want %v", got, tt.want)
+		})
 	}
 }
diff --git a/waflog/waflog_test.go b/waflog/waflog_test.go
index 2da0bf0..6e7979e 100644
--- a/waflog/waflog_test.go
+++ b/waflog/waflog_test.go
@@ -3,13 +3,14 @@ package waflog
 import (
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/coreruleset/go-ftw/config"
 )
 
 func TestNewFTWLogLines(t *testing.T) {
-	if err := config.NewConfigFromEnv(); err != nil {
-		t.Error(err)
-	}
+	err := config.NewConfigFromEnv()
+	assert.NoError(t, err)
 
 	ll := NewFTWLogLines()
 	// Loop through each option
@@ -22,17 +23,9 @@ func TestNewFTWLogLines(t *testing.T) {
 		// *House as the argument
 		opt(ll)
 	}
-	if ll.StartMarker == nil {
-		t.Errorf("Failed! StartMarker must be set")
-	}
-	if ll.EndMarker == nil {
-		t.Errorf("Failed! EndMarker must be set")
-	}
-	if ll.FileName != "test" {
-		t.Errorf("Failed! FileName must be set")
-	}
-
-	if err := ll.Cleanup(); err != nil {
-		t.Error(err)
-	}
+	assert.NotNil(t, ll.StartMarker, "Failed! StartMarker must be set")
+	assert.NotNil(t, ll.EndMarker, "Failed! EndMarker must be set")
+	assert.Equal(t, "test", ll.FileName, "Failed! FileName must be set")
+	err = ll.Cleanup()
+	assert.NoError(t, err)
 }