Repository: xenolf/lego
Pull request #671 (2018-10-11 23:56:57)

Homogenization of the DNS provider tests
- use the same way to name env var in tests
- use the same way to define the name of the tests
- add more tests


Patch:
diff --git a/acme/challenges.go b/acme/challenges.go
index 1140b107..d10f82b8 100644
--- a/acme/challenges.go
+++ b/acme/challenges.go
@@ -7,9 +7,11 @@ const (
 	// HTTP01 is the "http-01" ACME challenge https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#http
 	// Note: HTTP01ChallengePath returns the URL path to fulfill this challenge
 	HTTP01 = Challenge("http-01")
+
 	// DNS01 is the "dns-01" ACME challenge https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#dns
 	// Note: DNS01Record returns a DNS record which will fulfill this challenge
 	DNS01 = Challenge("dns-01")
+
 	// TLSALPN01 is the "tls-alpn-01" ACME challenge https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01
 	TLSALPN01 = Challenge("tls-alpn-01")
 )
diff --git a/acme/client.go b/acme/client.go
index 7af45033..4908d592 100644
--- a/acme/client.go
+++ b/acme/client.go
@@ -412,7 +412,7 @@ DNSNames:
 // the whole certificate will fail.
 func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (*CertificateResource, error) {
 	if len(domains) == 0 {
-		return nil, errors.New("No domains to obtain a certificate for")
+		return nil, errors.New("no domains to obtain a certificate for")
 	}
 
 	if bundle {
diff --git a/cli.go b/cli.go
index 102bb5a4..9f57e825 100644
--- a/cli.go
+++ b/cli.go
@@ -87,7 +87,7 @@ func main() {
 		{
 			Name:   "dnshelp",
 			Usage:  "Shows additional help for the --dns global option",
-			Action: dnshelp,
+			Action: dnsHelp,
 		},
 	}
 
@@ -187,7 +187,7 @@ func main() {
 	}
 }
 
-func dnshelp(c *cli.Context) error {
+func dnsHelp(_ *cli.Context) error {
 	fmt.Printf(
 		`Credentials for DNS providers must be passed through environment variables.
 
diff --git a/providers/dns/dnsmadeeasy/client.go b/providers/dns/dnsmadeeasy/client.go
index 54e87dcc..ba0727b9 100644
--- a/providers/dns/dnsmadeeasy/client.go
+++ b/providers/dns/dnsmadeeasy/client.go
@@ -38,11 +38,11 @@ type Client struct {
 // NewClient creates a DNSMadeEasy client
 func NewClient(apiKey string, apiSecret string) (*Client, error) {
 	if apiKey == "" {
-		return nil, fmt.Errorf("DNSMadeEasy: credentials missing: API key")
+		return nil, fmt.Errorf("credentials missing: API key")
 	}
 
 	if apiSecret == "" {
-		return nil, fmt.Errorf("DNSMadeEasy: credentials missing: API secret")
+		return nil, fmt.Errorf("credentials missing: API secret")
 	}
 
 	return &Client{
diff --git a/providers/dns/dnsmadeeasy/dnsmadeeasy.go b/providers/dns/dnsmadeeasy/dnsmadeeasy.go
index c0f580d5..519a4451 100644
--- a/providers/dns/dnsmadeeasy/dnsmadeeasy.go
+++ b/providers/dns/dnsmadeeasy/dnsmadeeasy.go
@@ -5,7 +5,6 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
-	"strconv"
 	"strings"
 	"time"
 
@@ -18,6 +17,7 @@ type Config struct {
 	BaseURL            string
 	APIKey             string
 	APISecret          string
+	Sandbox            bool
 	HTTPClient         *http.Client
 	PropagationTimeout time.Duration
 	PollingInterval    time.Duration
@@ -55,15 +55,8 @@ func NewDNSProvider() (*DNSProvider, error) {
 		return nil, fmt.Errorf("dnsmadeeasy: %v", err)
 	}
 
-	var baseURL string
-	if sandbox, _ := strconv.ParseBool(env.GetOrFile("DNSMADEEASY_SANDBOX")); sandbox {
-		baseURL = "https://api.sandbox.dnsmadeeasy.com/V2.0"
-	} else {
-		baseURL = "https://api.dnsmadeeasy.com/V2.0"
-	}
-
 	config := NewDefaultConfig()
-	config.BaseURL = baseURL
+	config.Sandbox = env.GetOrDefaultBool("DNSMADEEASY_SANDBOX", false)
 	config.APIKey = values["DNSMADEEASY_API_KEY"]
 	config.APISecret = values["DNSMADEEASY_API_SECRET"]
 
@@ -88,8 +81,15 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 		return nil, errors.New("dnsmadeeasy: the configuration of the DNS provider is nil")
 	}
 
-	if config.BaseURL == "" {
-		return nil, fmt.Errorf("dnsmadeeasy: base URL missing")
+	var baseURL string
+	if config.Sandbox {
+		baseURL = "https://api.sandbox.dnsmadeeasy.com/V2.0"
+	} else {
+		if len(config.BaseURL) > 0 {
+			baseURL = config.BaseURL
+		} else {
+			baseURL = "https://api.dnsmadeeasy.com/V2.0"
+		}
 	}
 
 	client, err := NewClient(config.APIKey, config.APISecret)
@@ -98,7 +98,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	}
 
 	client.HTTPClient = config.HTTPClient
-	client.BaseURL = config.BaseURL
+	client.BaseURL = baseURL
 
 	return &DNSProvider{
 		client: client,
diff --git a/providers/dns/fastdns/fastdns.go b/providers/dns/fastdns/fastdns.go
index 7fb6b3c0..9ef6cb0e 100644
--- a/providers/dns/fastdns/fastdns.go
+++ b/providers/dns/fastdns/fastdns.go
@@ -77,7 +77,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	}
 
 	if config.ClientToken == "" || config.ClientSecret == "" || config.AccessToken == "" || config.Host == "" {
-		return nil, fmt.Errorf("FastDNS credentials are missing")
+		return nil, fmt.Errorf("fastdns: credentials are missing")
 	}
 
 	return &DNSProvider{config: config}, nil
diff --git a/providers/dns/gandiv5/gandiv5.go b/providers/dns/gandiv5/gandiv5.go
index 04e9fa19..0962d159 100644
--- a/providers/dns/gandiv5/gandiv5.go
+++ b/providers/dns/gandiv5/gandiv5.go
@@ -102,6 +102,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 		config.BaseURL = defaultBaseURL
 	}
 
+	if config.TTL < minTTL {
+		return nil, fmt.Errorf("gandiv5: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
+	}
+
 	return &DNSProvider{
 		config:          config,
 		inProgressFQDNs: make(map[string]inProgressInfo),
@@ -112,10 +116,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
-	if d.config.TTL < minTTL {
-		d.config.TTL = minTTL // 300 is gandi minimum value for ttl
-	}
-
 	// find authZone
 	authZone, err := findZoneByFqdn(fqdn, acme.RecursiveNameservers)
 	if err != nil {
diff --git a/providers/dns/gcloud/fixtures/gce_account_service_file.json b/providers/dns/gcloud/fixtures/gce_account_service_file.json
new file mode 100644
index 00000000..c9b61682
--- /dev/null
+++ b/providers/dns/gcloud/fixtures/gce_account_service_file.json
@@ -0,0 +1,11 @@
+{
+  "project_id": "A",
+  "type": "service_account",
+  "client_email": "foo@bar.com",
+  "private_key_id": "pki",
+  "private_key": "pk",
+  "token_uri": "/token",
+  "client_secret": "secret",
+  "client_id": "C",
+  "refresh_token": "D"
+}
\ No newline at end of file
diff --git a/providers/dns/glesys/glesys.go b/providers/dns/glesys/glesys.go
index 69f61f77..4aab8744 100644
--- a/providers/dns/glesys/glesys.go
+++ b/providers/dns/glesys/glesys.go
@@ -93,6 +93,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 		return nil, fmt.Errorf("glesys: incomplete credentials provided")
 	}
 
+	if config.TTL < minTTL {
+		return nil, fmt.Errorf("glesys: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
+	}
+
 	return &DNSProvider{
 		config:        config,
 		activeRecords: make(map[string]int),
@@ -103,9 +107,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
-	if d.config.TTL < minTTL {
-		d.config.TTL = minTTL // 60 is GleSYS minimum value for ttl
-	}
 	// find authZone
 	authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
 	if err != nil {
diff --git a/providers/dns/nifcloud/client.go b/providers/dns/nifcloud/client.go
index dc10cbc2..24a8f52b 100644
--- a/providers/dns/nifcloud/client.go
+++ b/providers/dns/nifcloud/client.go
@@ -89,13 +89,17 @@ type ChangeInfo struct {
 }
 
 // NewClient Creates a new client of NIFCLOUD DNS
-func NewClient(accessKey string, secretKey string) *Client {
+func NewClient(accessKey string, secretKey string) (*Client, error) {
+	if len(accessKey) == 0 || len(secretKey) == 0 {
+		return nil, errors.New("credentials missing")
+	}
+
 	return &Client{
 		accessKey:  accessKey,
 		secretKey:  secretKey,
 		BaseURL:    defaultBaseURL,
 		HTTPClient: &http.Client{},
-	}
+	}, nil
 }
 
 // Client client of NIFCLOUD DNS
diff --git a/providers/dns/nifcloud/nifcloud.go b/providers/dns/nifcloud/nifcloud.go
index 6021cd51..c8cf0484 100644
--- a/providers/dns/nifcloud/nifcloud.go
+++ b/providers/dns/nifcloud/nifcloud.go
@@ -77,7 +77,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 		return nil, errors.New("nifcloud: the configuration of the DNS provider is nil")
 	}
 
-	client := NewClient(config.AccessKey, config.SecretKey)
+	client, err := NewClient(config.AccessKey, config.SecretKey)
+	if err != nil {
+		return nil, fmt.Errorf("nifcloud: %v", err)
+	}
 
 	if config.HTTPClient != nil {
 		client.HTTPClient = config.HTTPClient
diff --git a/providers/dns/rackspace/client.go b/providers/dns/rackspace/client.go
index ce203276..54b05c9d 100644
--- a/providers/dns/rackspace/client.go
+++ b/providers/dns/rackspace/client.go
@@ -16,20 +16,44 @@ type AuthData struct {
 	Auth `json:"auth"`
 }
 
-// Identity  Identity
+// Identity Identity
 type Identity struct {
-	Access struct {
-		ServiceCatalog []struct {
-			Endpoints []struct {
-				PublicURL string `json:"publicURL"`
-				TenantID  string `json:"tenantId"`
-			} `json:"endpoints"`
-			Name string `json:"name"`
-		} `json:"serviceCatalog"`
-		Token struct {
-			ID string `json:"id"`
-		} `json:"token"`
-	} `json:"access"`
+	Access Access `json:"access"`
+}
+
+// Access Access
+type Access struct {
+	ServiceCatalog []ServiceCatalog `json:"serviceCatalog"`
+	Token          Token            `json:"token"`
+}
+
+// Token Token
+type Token struct {
+	ID string `json:"id"`
+}
+
+// ServiceCatalog ServiceCatalog
+type ServiceCatalog struct {
+	Endpoints []Endpoint `json:"endpoints"`
+	Name      string     `json:"name"`
+}
+
+// Endpoint Endpoint
+type Endpoint struct {
+	PublicURL string `json:"publicURL"`
+	TenantID  string `json:"tenantId"`
+}
+
+// ZoneSearchResponse represents the response when querying Rackspace DNS zones
+type ZoneSearchResponse struct {
+	TotalEntries int          `json:"totalEntries"`
+	HostedZones  []HostedZone `json:"domains"`
+}
+
+// HostedZone HostedZone
+type HostedZone struct {
+	ID   int    `json:"id"`
+	Name string `json:"name"`
 }
 
 // Records is the list of records sent/received from the DNS API
diff --git a/providers/dns/rackspace/rackspace.go b/providers/dns/rackspace/rackspace.go
index 2a35c907..7b5e73d4 100644
--- a/providers/dns/rackspace/rackspace.go
+++ b/providers/dns/rackspace/rackspace.go
@@ -89,39 +89,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 		return nil, fmt.Errorf("rackspace: credentials missing")
 	}
 
-	authData := AuthData{
-		Auth: Auth{
-			APIKeyCredentials: APIKeyCredentials{
-				Username: config.APIUser,
-				APIKey:   config.APIKey,
-			},
-		},
-	}
-
-	body, err := json.Marshal(authData)
-	if err != nil {
-		return nil, err
-	}
-
-	req, err := http.NewRequest(http.MethodPost, config.BaseURL, bytes.NewReader(body))
-	if err != nil {
-		return nil, err
-	}
-	req.Header.Set("Content-Type", "application/json")
-
-	// client := &http.Client{Timeout: 30 * time.Second}
-	resp, err := config.HTTPClient.Do(req)
-	if err != nil {
-		return nil, fmt.Errorf("rackspace: error querying Identity API: %v", err)
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("rackspace: authentication failed: response code: %d", resp.StatusCode)
-	}
-
-	var identity Identity
-	err = json.NewDecoder(resp.Body).Decode(&identity)
+	identity, err := login(config)
 	if err != nil {
 		return nil, fmt.Errorf("rackspace: %v", err)
 	}
@@ -134,6 +102,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 			break
 		}
 	}
+
 	if dnsEndpoint == "" {
 		return nil, fmt.Errorf("rackspace: failed to populate DNS endpoint, check Rackspace API for changes")
 	}
@@ -149,6 +118,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 // Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
+
 	zoneID, err := d.getHostedZoneID(fqdn)
 	if err != nil {
 		return fmt.Errorf("rackspace: %v", err)
@@ -178,6 +148,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 // CleanUp removes the TXT record matching the specified parameters
 func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
 	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
+
 	zoneID, err := d.getHostedZoneID(fqdn)
 	if err != nil {
 		return fmt.Errorf("rackspace: %v", err)
@@ -204,15 +175,6 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 // getHostedZoneID performs a lookup to get the DNS zone which needs
 // modifying for a given FQDN
 func (d *DNSProvider) getHostedZoneID(fqdn string) (int, error) {
-	// HostedZones represents the response when querying Rackspace DNS zones
-	type ZoneSearchResponse struct {
-		TotalEntries int `json:"totalEntries"`
-		HostedZones  []struct {
-			ID   int    `json:"id"`
-			Name string `json:"name"`
-		} `json:"domains"`
-	}
-
 	authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
 	if err != nil {
 		return 0, err
@@ -250,8 +212,7 @@ func (d *DNSProvider) findTxtRecord(fqdn string, zoneID int) (*Record, error) {
 		return nil, err
 	}
 
-	recordsLength := len(records.Record)
-	switch recordsLength {
+	switch len(records.Record) {
 	case 1:
 	case 0:
 		return nil, fmt.Errorf("no TXT record found for %s", fqdn)
@@ -265,6 +226,7 @@ func (d *DNSProvider) findTxtRecord(fqdn string, zoneID int) (*Record, error) {
 // makeRequest is a wrapper function used for making DNS API requests
 func (d *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
 	url := d.cloudDNSEndpoint + uri
+
 	req, err := http.NewRequest(method, url, body)
 	if err != nil {
 		return nil, err
@@ -292,3 +254,44 @@ func (d *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawM
 
 	return r, nil
 }
+
+func login(config *Config) (*Identity, error) {
+	authData := AuthData{
+		Auth: Auth{
+			APIKeyCredentials: APIKeyCredentials{
+				Username: config.APIUser,
+				APIKey:   config.APIKey,
+			},
+		},
+	}
+
+	body, err := json.Marshal(authData)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http.NewRequest(http.MethodPost, config.BaseURL, bytes.NewReader(body))
+	if err != nil {
+		return nil, err
+	}
+
+	req.Header.Set("Content-Type", "application/json")
+
+	resp, err := config.HTTPClient.Do(req)
+	if err != nil {
+		return nil, fmt.Errorf("error querying Identity API: %v", err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("authentication failed: response code: %d", resp.StatusCode)
+	}
+
+	var identity Identity
+	err = json.NewDecoder(resp.Body).Decode(&identity)
+	if err != nil {
+		return nil, err
+	}
+
+	return &identity, nil
+}


Test patch:
diff --git a/acme/client_test.go b/acme/client_test.go
index b18047a0..e14444ee 100644
--- a/acme/client_test.go
+++ b/acme/client_test.go
@@ -217,7 +217,7 @@ func TestValidate(t *testing.T) {
 
 			err := validate(j, "example.com", ts.URL, challenge{Type: "http-01", Token: "token"})
 			if test.want == "" {
-				assert.NoError(t, err)
+				require.NoError(t, err)
 			} else {
 				assert.Error(t, err)
 				assert.Contains(t, err.Error(), test.want)
@@ -262,7 +262,7 @@ func TestGetChallenges(t *testing.T) {
 	require.NoError(t, err, "Could not create client")
 
 	_, err = client.createOrderForIdentifiers([]string{"example.com"})
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestResolveAccountByKey(t *testing.T) {
diff --git a/acme/http_challenge_test.go b/acme/http_challenge_test.go
index ba0e8bf7..17c4a4e7 100644
--- a/acme/http_challenge_test.go
+++ b/acme/http_challenge_test.go
@@ -48,7 +48,7 @@ func TestHTTPChallenge(t *testing.T) {
 	clientChallenge := challenge{Type: string(HTTP01), Token: "http1"}
 
 	err = solver.Solve(clientChallenge, "localhost:23457")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestHTTPChallengeInvalidPort(t *testing.T) {
diff --git a/acme/tls_alpn_challenge_test.go b/acme/tls_alpn_challenge_test.go
index 4b090177..b8426593 100644
--- a/acme/tls_alpn_challenge_test.go
+++ b/acme/tls_alpn_challenge_test.go
@@ -20,7 +20,7 @@ func TestTLSALPNChallenge(t *testing.T) {
 		conn, err := tls.Dial("tcp", domain, &tls.Config{
 			InsecureSkipVerify: true,
 		})
-		assert.NoError(t, err, "Expected to connect to challenge server without an error")
+		require.NoError(t, err, "Expected to connect to challenge server without an error")
 
 		// Expect the server to only return one certificate
 		connState := conn.ConnectionState()
@@ -67,7 +67,7 @@ func TestTLSALPNChallenge(t *testing.T) {
 	clientChallenge := challenge{Type: string(TLSALPN01), Token: "tlsalpn1"}
 
 	err = solver.Solve(clientChallenge, domain)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestTLSALPNChallengeInvalidPort(t *testing.T) {
diff --git a/providers/dns/alidns/alidns_test.go b/providers/dns/alidns/alidns_test.go
index ee4f6233..d809cdbf 100644
--- a/providers/dns/alidns/alidns_test.go
+++ b/providers/dns/alidns/alidns_test.go
@@ -5,91 +5,171 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	alidnsLiveTest  bool
-	alidnsAPIKey    string
-	alidnsSecretKey string
-	alidnsDomain    string
+	liveTest         bool
+	envTestAPIKey    string
+	envTestSecretKey string
+	envTestDomain    string
 )
 
 func init() {
-	alidnsAPIKey = os.Getenv("ALICLOUD_ACCESS_KEY")
-	alidnsSecretKey = os.Getenv("ALICLOUD_SECRET_KEY")
-	alidnsDomain = os.Getenv("ALIDNS_DOMAIN")
+	envTestAPIKey = os.Getenv("ALICLOUD_ACCESS_KEY")
+	envTestSecretKey = os.Getenv("ALICLOUD_SECRET_KEY")
+	envTestDomain = os.Getenv("ALIDNS_DOMAIN")
 
-	if len(alidnsAPIKey) > 0 && len(alidnsSecretKey) > 0 && len(alidnsDomain) > 0 {
-		alidnsLiveTest = true
+	if len(envTestAPIKey) > 0 && len(envTestSecretKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("ALICLOUD_ACCESS_KEY", alidnsAPIKey)
-	os.Setenv("ALICLOUD_SECRET_KEY", alidnsSecretKey)
+	os.Setenv("ALICLOUD_ACCESS_KEY", envTestAPIKey)
+	os.Setenv("ALICLOUD_SECRET_KEY", envTestSecretKey)
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("ALICLOUD_ACCESS_KEY", "")
-	os.Setenv("ALICLOUD_SECRET_KEY", "")
-
-	config := NewDefaultConfig()
-	config.APIKey = "123"
-	config.SecretKey = "123"
-
-	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-}
-
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("ALICLOUD_ACCESS_KEY", "123")
-	os.Setenv("ALICLOUD_SECRET_KEY", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"ALICLOUD_ACCESS_KEY": "123",
+				"ALICLOUD_SECRET_KEY": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"ALICLOUD_ACCESS_KEY": "",
+				"ALICLOUD_SECRET_KEY": "",
+			},
+			expected: "alicloud: some credentials information are missing: ALICLOUD_ACCESS_KEY,ALICLOUD_SECRET_KEY",
+		},
+		{
+			desc: "missing access key",
+			envVars: map[string]string{
+				"ALICLOUD_ACCESS_KEY": "",
+				"ALICLOUD_SECRET_KEY": "456",
+			},
+			expected: "alicloud: some credentials information are missing: ALICLOUD_ACCESS_KEY",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"ALICLOUD_ACCESS_KEY": "123",
+				"ALICLOUD_SECRET_KEY": "",
+			},
+			expected: "alicloud: some credentials information are missing: ALICLOUD_SECRET_KEY",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("ALICLOUD_ACCESS_KEY", "")
-	os.Setenv("ALICLOUD_SECRET_KEY", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		apiKey    string
+		secretKey string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			apiKey:    "123",
+			secretKey: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "alicloud: credentials missing",
+		},
+		{
+			desc:      "missing api key",
+			secretKey: "456",
+			expected:  "alicloud: credentials missing",
+		},
+		{
+			desc:     "missing secret key",
+			apiKey:   "123",
+			expected: "alicloud: credentials missing",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "alicloud: some credentials information are missing: ALICLOUD_ACCESS_KEY,ALICLOUD_SECRET_KEY")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("ALICLOUD_ACCESS_KEY")
+			os.Unsetenv("ALICLOUD_SECRET_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.SecretKey = test.secretKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestCloudXNSPresent(t *testing.T) {
-	if !alidnsLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.APIKey = alidnsAPIKey
-	config.SecretKey = alidnsSecretKey
-
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	err = provider.Present(alidnsDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestLivednspodCleanUp(t *testing.T) {
-	if !alidnsLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	config := NewDefaultConfig()
-	config.APIKey = alidnsAPIKey
-	config.SecretKey = alidnsSecretKey
+	time.Sleep(1 * time.Second)
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-	err = provider.CleanUp(alidnsDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/auroradns/auroradns_test.go b/providers/dns/auroradns/auroradns_test.go
index 81ce3740..1d9c8152 100644
--- a/providers/dns/auroradns/auroradns_test.go
+++ b/providers/dns/auroradns/auroradns_test.go
@@ -5,36 +5,185 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
-var fakeAuroraDNSUserID = "asdf1234"
-var fakeAuroraDNSKey = "key"
+var (
+	envTestUserID string
+	envTestKey    string
+)
+
+func init() {
+	envTestUserID = os.Getenv("AURORA_USER_ID")
+	envTestKey = os.Getenv("AURORA_KEY")
+}
+
+func restoreEnv() {
+	os.Setenv("AURORA_USER_ID", envTestUserID)
+	os.Setenv("AURORA_KEY", envTestKey)
+}
+
+func setupTest() (*DNSProvider, *http.ServeMux, func()) {
+	handler := http.NewServeMux()
+	server := httptest.NewServer(handler)
+
+	config := NewDefaultConfig()
+	config.UserID = "asdf1234"
+	config.Key = "key"
+	config.BaseURL = server.URL
+
+	provider, err := NewDNSProviderConfig(config)
+	if err != nil {
+		panic(err)
+	}
 
-func TestAuroraDNSPresent(t *testing.T) {
-	var requestReceived bool
+	return provider, handler, server.Close
+}
 
-	mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		if r.Method == http.MethodGet && r.URL.Path == "/zones" {
-			w.WriteHeader(http.StatusCreated)
-			fmt.Fprintf(w, `[{
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"AURORA_USER_ID": "123",
+				"AURORA_KEY":     "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"AURORA_USER_ID": "",
+				"AURORA_KEY":     "",
+			},
+			expected: "aurora: some credentials information are missing: AURORA_USER_ID,AURORA_KEY",
+		},
+		{
+			desc: "missing user id",
+			envVars: map[string]string{
+				"AURORA_USER_ID": "",
+				"AURORA_KEY":     "456",
+			},
+			expected: "aurora: some credentials information are missing: AURORA_USER_ID",
+		},
+		{
+			desc: "missing key",
+			envVars: map[string]string{
+				"AURORA_USER_ID": "123",
+				"AURORA_KEY":     "",
+			},
+			expected: "aurora: some credentials information are missing: AURORA_KEY",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		userID   string
+		key      string
+		expected string
+	}{
+		{
+			desc:   "success",
+			userID: "123",
+			key:    "456",
+		},
+		{
+			desc:     "missing credentials",
+			userID:   "",
+			key:      "",
+			expected: "aurora: some credentials information are missing",
+		},
+		{
+			desc:     "missing user id",
+			userID:   "",
+			key:      "456",
+			expected: "aurora: some credentials information are missing",
+		},
+		{
+			desc:     "missing key",
+			userID:   "123",
+			key:      "",
+			expected: "aurora: some credentials information are missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("AURORA_USER_ID")
+			os.Unsetenv("AURORA_KEY")
+
+			config := NewDefaultConfig()
+			config.UserID = test.userID
+			config.Key = test.key
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestDNSProvider_Present(t *testing.T) {
+	provider, mux, tearDown := setupTest()
+	defer tearDown()
+
+	mux.HandleFunc("/zones", func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodGet, r.Method, "method")
+
+		w.WriteHeader(http.StatusCreated)
+		fmt.Fprintf(w, `[{
 			        "id":   "c56a4180-65aa-42ec-a945-5fd21dec0538",
 			        "name": "example.com"
 			      }]`)
-			return
-		}
+	})
 
-		requestReceived = true
-
-		assert.Equal(t, http.MethodPost, r.Method, "method")
-		assert.Equal(t, "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records", r.URL.Path, "Path")
+	mux.HandleFunc("/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records", func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPost, r.Method)
 		assert.Equal(t, "application/json", r.Header.Get("Content-Type"), "Content-Type")
 
 		reqBody, err := ioutil.ReadAll(r.Body)
-		require.NoError(t, err, "reading request body")
+		require.NoError(t, err)
 		assert.Equal(t, `{"type":"TXT","name":"_acme-challenge","content":"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI","ttl":300}`, string(reqBody))
 
 		w.WriteHeader(http.StatusCreated)
@@ -44,74 +193,50 @@ func TestAuroraDNSPresent(t *testing.T) {
 		      "name": "_acme-challenge",
 		      "ttl":  300
 		    }`)
-	}))
-
-	defer mock.Close()
+	})
 
-	config := NewDefaultConfig()
-	config.UserID = fakeAuroraDNSUserID
-	config.Key = fakeAuroraDNSKey
-	config.BaseURL = mock.URL
-
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-	require.NotNil(t, provider)
-
-	err = provider.Present("example.com", "", "foobar")
+	err := provider.Present("example.com", "", "foobar")
 	require.NoError(t, err, "fail to create TXT record")
-
-	assert.True(t, requestReceived, "Expected request to be received by mock backend, but it wasn't")
 }
 
-func TestAuroraDNSCleanUp(t *testing.T) {
-	var requestReceived bool
+func TestDNSProvider_CleanUp(t *testing.T) {
+	provider, mux, tearDown := setupTest()
+	defer tearDown()
 
-	mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		if r.Method == http.MethodGet && r.URL.Path == "/zones" {
-			w.WriteHeader(http.StatusCreated)
-			fmt.Fprintf(w, `[{
+	mux.HandleFunc("/zones", func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodGet, r.Method)
+
+		w.WriteHeader(http.StatusCreated)
+		fmt.Fprintf(w, `[{
 			        "id":   "c56a4180-65aa-42ec-a945-5fd21dec0538",
 			        "name": "example.com"
 			      }]`)
-			return
-		}
+	})
 
-		if r.Method == http.MethodPost && r.URL.Path == "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records" {
-			w.WriteHeader(http.StatusCreated)
-			fmt.Fprintf(w, `{
+	mux.HandleFunc("/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records", func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPost, r.Method)
+
+		w.WriteHeader(http.StatusCreated)
+		fmt.Fprintf(w, `{
 			        "id":   "ec56a4180-65aa-42ec-a945-5fd21dec0538",
 			        "type": "TXT",
 			        "name": "_acme-challenge",
 			        "ttl":  300
 			      }`)
-			return
-		}
+	})
 
-		requestReceived = true
+	mux.HandleFunc("/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records/ec56a4180-65aa-42ec-a945-5fd21dec0538", func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodDelete, r.Method)
 
-		assert.Equal(t, http.MethodDelete, r.Method, "method")
-		assert.Equal(t, "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records/ec56a4180-65aa-42ec-a945-5fd21dec0538", r.URL.Path, "Path")
 		assert.Equal(t, "application/json", r.Header.Get("Content-Type"), "Content-Type")
 
 		w.WriteHeader(http.StatusCreated)
 		fmt.Fprintf(w, `{}`)
-	}))
-	defer mock.Close()
-
-	config := NewDefaultConfig()
-	config.UserID = fakeAuroraDNSUserID
-	config.Key = fakeAuroraDNSKey
-	config.BaseURL = mock.URL
-
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-	require.NotNil(t, provider)
+	})
 
-	err = provider.Present("example.com", "", "foobar")
+	err := provider.Present("example.com", "", "foobar")
 	require.NoError(t, err, "fail to create TXT record")
 
 	err = provider.CleanUp("example.com", "", "foobar")
 	require.NoError(t, err, "fail to remove TXT record")
-
-	assert.True(t, requestReceived, "Expected request to be received by mock backend, but it wasn't")
 }
diff --git a/providers/dns/azure/azure_test.go b/providers/dns/azure/azure_test.go
index 85dc14c9..1019ecc2 100644
--- a/providers/dns/azure/azure_test.go
+++ b/providers/dns/azure/azure_test.go
@@ -5,112 +5,270 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	azureLiveTest       bool
-	azureClientID       string
-	azureClientSecret   string
-	azureSubscriptionID string
-	azureTenantID       string
-	azureResourceGroup  string
-	azureDomain         string
+	liveTest              bool
+	envTestClientID       string
+	envTestClientSecret   string
+	envTestSubscriptionID string
+	envTestTenantID       string
+	envTestResourceGroup  string
+	envTestDomain         string
 )
 
 func init() {
-	azureClientID = os.Getenv("AZURE_CLIENT_ID")
-	azureClientSecret = os.Getenv("AZURE_CLIENT_SECRET")
-	azureSubscriptionID = os.Getenv("AZURE_SUBSCRIPTION_ID")
-	azureTenantID = os.Getenv("AZURE_TENANT_ID")
-	azureResourceGroup = os.Getenv("AZURE_RESOURCE_GROUP")
-	azureDomain = os.Getenv("AZURE_DOMAIN")
-	if len(azureClientID) > 0 && len(azureClientSecret) > 0 {
-		azureLiveTest = true
+	envTestClientID = os.Getenv("AZURE_CLIENT_ID")
+	envTestClientSecret = os.Getenv("AZURE_CLIENT_SECRET")
+	envTestSubscriptionID = os.Getenv("AZURE_SUBSCRIPTION_ID")
+	envTestTenantID = os.Getenv("AZURE_TENANT_ID")
+	envTestResourceGroup = os.Getenv("AZURE_RESOURCE_GROUP")
+	envTestDomain = os.Getenv("AZURE_DOMAIN")
+
+	if len(envTestClientID) > 0 && len(envTestClientSecret) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("AZURE_CLIENT_ID", azureClientID)
-	os.Setenv("AZURE_SUBSCRIPTION_ID", azureSubscriptionID)
+	os.Setenv("AZURE_CLIENT_ID", envTestClientID)
+	os.Setenv("AZURE_CLIENT_SECRET", envTestClientSecret)
+	os.Setenv("AZURE_SUBSCRIPTION_ID", envTestSubscriptionID)
+	os.Setenv("AZURE_TENANT_ID", envTestTenantID)
+	os.Setenv("AZURE_RESOURCE_GROUP", envTestResourceGroup)
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	if !azureLiveTest {
-		t.Skip("skipping live test (requires credentials)")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "A",
+				"AZURE_CLIENT_SECRET":   "B",
+				"AZURE_SUBSCRIPTION_ID": "C",
+				"AZURE_TENANT_ID":       "D",
+				"AZURE_RESOURCE_GROUP":  "E",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "",
+				"AZURE_CLIENT_SECRET":   "",
+				"AZURE_SUBSCRIPTION_ID": "",
+				"AZURE_TENANT_ID":       "",
+				"AZURE_RESOURCE_GROUP":  "",
+			},
+			expected: "azure: some credentials information are missing: AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_SUBSCRIPTION_ID,AZURE_TENANT_ID,AZURE_RESOURCE_GROUP",
+		},
+		{
+			desc: "missing client id",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "",
+				"AZURE_CLIENT_SECRET":   "B",
+				"AZURE_SUBSCRIPTION_ID": "C",
+				"AZURE_TENANT_ID":       "D",
+				"AZURE_RESOURCE_GROUP":  "E",
+			},
+			expected: "azure: some credentials information are missing: AZURE_CLIENT_ID",
+		},
+		{
+			desc: "missing client secret",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "A",
+				"AZURE_CLIENT_SECRET":   "",
+				"AZURE_SUBSCRIPTION_ID": "C",
+				"AZURE_TENANT_ID":       "D",
+				"AZURE_RESOURCE_GROUP":  "E",
+			},
+			expected: "azure: some credentials information are missing: AZURE_CLIENT_SECRET",
+		},
+		{
+			desc: "missing subscription id",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "A",
+				"AZURE_CLIENT_SECRET":   "B",
+				"AZURE_SUBSCRIPTION_ID": "",
+				"AZURE_TENANT_ID":       "D",
+				"AZURE_RESOURCE_GROUP":  "E",
+			},
+			expected: "azure: some credentials information are missing: AZURE_SUBSCRIPTION_ID",
+		},
+		{
+			desc: "missing tenant id",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "A",
+				"AZURE_CLIENT_SECRET":   "B",
+				"AZURE_SUBSCRIPTION_ID": "C",
+				"AZURE_TENANT_ID":       "",
+				"AZURE_RESOURCE_GROUP":  "E",
+			},
+			expected: "azure: some credentials information are missing: AZURE_TENANT_ID",
+		},
+		{
+			desc: "missing resource group",
+			envVars: map[string]string{
+				"AZURE_CLIENT_ID":       "A",
+				"AZURE_CLIENT_SECRET":   "B",
+				"AZURE_SUBSCRIPTION_ID": "C",
+				"AZURE_TENANT_ID":       "D",
+				"AZURE_RESOURCE_GROUP":  "",
+			},
+			expected: "azure: some credentials information are missing: AZURE_RESOURCE_GROUP",
+		},
 	}
 
-	defer restoreEnv()
-	os.Setenv("AZURE_CLIENT_ID", "")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
 
-	config := NewDefaultConfig()
-	config.ClientID = azureClientID
-	config.ClientSecret = azureClientSecret
-	config.SubscriptionID = azureSubscriptionID
-	config.TenantID = azureTenantID
-	config.ResourceGroup = azureResourceGroup
+			p, err := NewDNSProvider()
 
-	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	if !azureLiveTest {
-		t.Skip("skipping live test (requires credentials)")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc           string
+		clientID       string
+		clientSecret   string
+		subscriptionID string
+		tenantID       string
+		resourceGroup  string
+		expected       string
+	}{
+		{
+			desc:           "success",
+			clientID:       "A",
+			clientSecret:   "B",
+			subscriptionID: "C",
+			tenantID:       "D",
+			resourceGroup:  "E",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "azure: some credentials information are missing",
+		},
+		{
+			desc:           "missing client id",
+			clientID:       "",
+			clientSecret:   "B",
+			subscriptionID: "C",
+			tenantID:       "D",
+			resourceGroup:  "E",
+			expected:       "azure: some credentials information are missing",
+		},
+		{
+			desc:           "missing client secret",
+			clientID:       "A",
+			clientSecret:   "",
+			subscriptionID: "C",
+			tenantID:       "D",
+			resourceGroup:  "E",
+			expected:       "azure: some credentials information are missing",
+		},
+		{
+			desc:           "missing subscription id",
+			clientID:       "A",
+			clientSecret:   "B",
+			subscriptionID: "",
+			tenantID:       "D",
+			resourceGroup:  "E",
+			expected:       "azure: some credentials information are missing",
+		},
+		{
+			desc:           "missing tenant id",
+			clientID:       "A",
+			clientSecret:   "B",
+			subscriptionID: "C",
+			tenantID:       "",
+			resourceGroup:  "E",
+			expected:       "azure: some credentials information are missing",
+		},
+		{
+			desc:           "missing resource group",
+			clientID:       "A",
+			clientSecret:   "B",
+			subscriptionID: "C",
+			tenantID:       "D",
+			resourceGroup:  "",
+			expected:       "azure: some credentials information are missing",
+		},
 	}
 
-	defer restoreEnv()
-	os.Setenv("AZURE_CLIENT_ID", "other")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("AZURE_CLIENT_ID")
+			os.Unsetenv("AZURE_CLIENT_SECRET")
+			os.Unsetenv("AZURE_SUBSCRIPTION_ID")
+			os.Unsetenv("AZURE_TENANT_ID")
+			os.Unsetenv("AZURE_RESOURCE_GROUP")
 
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
-}
+			config := NewDefaultConfig()
+			config.ClientID = test.clientID
+			config.ClientSecret = test.clientSecret
+			config.SubscriptionID = test.subscriptionID
+			config.TenantID = test.tenantID
+			config.ResourceGroup = test.resourceGroup
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("AZURE_SUBSCRIPTION_ID", "")
+			p, err := NewDNSProviderConfig(config)
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "azure: some credentials information are missing: AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_SUBSCRIPTION_ID,AZURE_TENANT_ID,AZURE_RESOURCE_GROUP")
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestLiveAzurePresent(t *testing.T) {
-	if !azureLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.ClientID = azureClientID
-	config.ClientSecret = azureClientSecret
-	config.SubscriptionID = azureSubscriptionID
-	config.TenantID = azureTenantID
-	config.ResourceGroup = azureResourceGroup
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-
-	err = provider.Present(azureDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestLiveAzureCleanUp(t *testing.T) {
-	if !azureLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.ClientID = azureClientID
-	config.ClientSecret = azureClientSecret
-	config.SubscriptionID = azureSubscriptionID
-	config.TenantID = azureTenantID
-	config.ResourceGroup = azureResourceGroup
-
-	provider, err := NewDNSProviderConfig(config)
-
-	time.Sleep(time.Second * 1)
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	assert.NoError(t, err)
+	time.Sleep(1 * time.Second)
 
-	err = provider.CleanUp(azureDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/bluecat/bluecat_test.go b/providers/dns/bluecat/bluecat_test.go
index 0362e58a..15649a8d 100644
--- a/providers/dns/bluecat/bluecat_test.go
+++ b/providers/dns/bluecat/bluecat_test.go
@@ -3,61 +3,277 @@ package bluecat
 import (
 	"os"
 	"testing"
-
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	bluecatLiveTest   bool
-	bluecatServer     string
-	bluecatUserName   string
-	bluecatPassword   string
-	bluecatConfigName string
-	bluecatDNSView    string
-	bluecatDomain     string
+	liveTest          bool
+	envTestServer     string
+	envTestUserName   string
+	envTestPassword   string
+	envTestConfigName string
+	envTestDNSView    string
+	envTestDomain     string
 )
 
 func init() {
-	bluecatServer = os.Getenv("BLUECAT_SERVER_URL")
-	bluecatUserName = os.Getenv("BLUECAT_USER_NAME")
-	bluecatPassword = os.Getenv("BLUECAT_PASSWORD")
-	bluecatDomain = os.Getenv("BLUECAT_DOMAIN")
-	bluecatConfigName = os.Getenv("BLUECAT_CONFIG_NAME")
-	bluecatDNSView = os.Getenv("BLUECAT_DNS_VIEW")
-	if len(bluecatServer) > 0 &&
-		len(bluecatDomain) > 0 &&
-		len(bluecatUserName) > 0 &&
-		len(bluecatPassword) > 0 &&
-		len(bluecatConfigName) > 0 &&
-		len(bluecatDNSView) > 0 {
-		bluecatLiveTest = true
+	envTestServer = os.Getenv("BLUECAT_SERVER_URL")
+	envTestUserName = os.Getenv("BLUECAT_USER_NAME")
+	envTestPassword = os.Getenv("BLUECAT_PASSWORD")
+	envTestDomain = os.Getenv("BLUECAT_DOMAIN")
+	envTestConfigName = os.Getenv("BLUECAT_CONFIG_NAME")
+	envTestDNSView = os.Getenv("BLUECAT_DNS_VIEW")
+
+	if len(envTestServer) > 0 &&
+		len(envTestDomain) > 0 &&
+		len(envTestUserName) > 0 &&
+		len(envTestPassword) > 0 &&
+		len(envTestConfigName) > 0 &&
+		len(envTestDNSView) > 0 {
+		liveTest = true
+	}
+}
+
+func restoreEnv() {
+	os.Setenv("BLUECAT_SERVER_URL", envTestServer)
+	os.Setenv("BLUECAT_USER_NAME", envTestUserName)
+	os.Setenv("BLUECAT_PASSWORD", envTestPassword)
+	os.Setenv("BLUECAT_CONFIG_NAME", envTestConfigName)
+	os.Setenv("BLUECAT_DNS_VIEW", envTestDNSView)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "http://localhost",
+				"BLUECAT_USER_NAME":   "A",
+				"BLUECAT_PASSWORD":    "B",
+				"BLUECAT_CONFIG_NAME": "C",
+				"BLUECAT_DNS_VIEW":    "D",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "",
+				"BLUECAT_USER_NAME":   "",
+				"BLUECAT_PASSWORD":    "",
+				"BLUECAT_CONFIG_NAME": "",
+				"BLUECAT_DNS_VIEW":    "",
+			},
+			expected: "bluecat: some credentials information are missing: BLUECAT_SERVER_URL,BLUECAT_USER_NAME,BLUECAT_PASSWORD,BLUECAT_CONFIG_NAME,BLUECAT_DNS_VIEW",
+		},
+		{
+			desc: "missing server url",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "",
+				"BLUECAT_USER_NAME":   "A",
+				"BLUECAT_PASSWORD":    "B",
+				"BLUECAT_CONFIG_NAME": "C",
+				"BLUECAT_DNS_VIEW":    "D",
+			},
+			expected: "bluecat: some credentials information are missing: BLUECAT_SERVER_URL",
+		},
+		{
+			desc: "missing username",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "http://localhost",
+				"BLUECAT_USER_NAME":   "",
+				"BLUECAT_PASSWORD":    "B",
+				"BLUECAT_CONFIG_NAME": "C",
+				"BLUECAT_DNS_VIEW":    "D",
+			},
+			expected: "bluecat: some credentials information are missing: BLUECAT_USER_NAME",
+		},
+		{
+			desc: "missing password",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "http://localhost",
+				"BLUECAT_USER_NAME":   "A",
+				"BLUECAT_PASSWORD":    "",
+				"BLUECAT_CONFIG_NAME": "C",
+				"BLUECAT_DNS_VIEW":    "D",
+			},
+			expected: "bluecat: some credentials information are missing: BLUECAT_PASSWORD",
+		},
+		{
+			desc: "missing config name",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "http://localhost",
+				"BLUECAT_USER_NAME":   "A",
+				"BLUECAT_PASSWORD":    "B",
+				"BLUECAT_CONFIG_NAME": "",
+				"BLUECAT_DNS_VIEW":    "D",
+			},
+			expected: "bluecat: some credentials information are missing: BLUECAT_CONFIG_NAME",
+		},
+		{
+			desc: "missing DNS view",
+			envVars: map[string]string{
+				"BLUECAT_SERVER_URL":  "http://localhost",
+				"BLUECAT_USER_NAME":   "A",
+				"BLUECAT_PASSWORD":    "B",
+				"BLUECAT_CONFIG_NAME": "C",
+				"BLUECAT_DNS_VIEW":    "",
+			},
+			expected: "bluecat: some credentials information are missing: BLUECAT_DNS_VIEW",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
 	}
 }
 
-func TestLiveBluecatPresent(t *testing.T) {
-	if !bluecatLiveTest {
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc       string
+		baseURL    string
+		userName   string
+		password   string
+		configName string
+		dnsView    string
+		expected   string
+	}{
+		{
+			desc:       "success",
+			baseURL:    "http://localhost",
+			userName:   "A",
+			password:   "B",
+			configName: "C",
+			dnsView:    "D",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "bluecat: credentials missing",
+		},
+		{
+			desc:       "missing base URL",
+			baseURL:    "",
+			userName:   "A",
+			password:   "B",
+			configName: "C",
+			dnsView:    "D",
+			expected:   "bluecat: credentials missing",
+		},
+		{
+			desc:       "missing username",
+			baseURL:    "http://localhost",
+			userName:   "",
+			password:   "B",
+			configName: "C",
+			dnsView:    "D",
+			expected:   "bluecat: credentials missing",
+		},
+		{
+			desc:       "missing password",
+			baseURL:    "http://localhost",
+			userName:   "A",
+			password:   "",
+			configName: "C",
+			dnsView:    "D",
+			expected:   "bluecat: credentials missing",
+		},
+		{
+			desc:       "missing config name",
+			baseURL:    "http://localhost",
+			userName:   "A",
+			password:   "B",
+			configName: "",
+			dnsView:    "D",
+			expected:   "bluecat: credentials missing",
+		},
+		{
+			desc:       "missing DNS view",
+			baseURL:    "http://localhost",
+			userName:   "A",
+			password:   "B",
+			configName: "C",
+			dnsView:    "",
+			expected:   "bluecat: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("BLUECAT_SERVER_URL")
+			os.Unsetenv("BLUECAT_USER_NAME")
+			os.Unsetenv("BLUECAT_PASSWORD")
+			os.Unsetenv("BLUECAT_CONFIG_NAME")
+			os.Unsetenv("BLUECAT_DNS_VIEW")
+
+			config := NewDefaultConfig()
+			config.BaseURL = test.baseURL
+			config.UserName = test.userName
+			config.Password = test.password
+			config.ConfigName = test.configName
+			config.DNSView = test.dnsView
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.Present(bluecatDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestLiveBluecatCleanUp(t *testing.T) {
-	if !bluecatLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
+
+	time.Sleep(time.Second * 1)
 
-	err = provider.CleanUp(bluecatDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/cloudflare/cloudflare_test.go b/providers/dns/cloudflare/cloudflare_test.go
index 9214f32c..5605cd03 100644
--- a/providers/dns/cloudflare/cloudflare_test.go
+++ b/providers/dns/cloudflare/cloudflare_test.go
@@ -10,24 +10,24 @@ import (
 )
 
 var (
-	cflareLiveTest bool
-	cflareEmail    string
-	cflareAPIKey   string
-	cflareDomain   string
+	liveTest      bool
+	envTestEmail  string
+	envTestAPIKey string
+	envTestDomain string
 )
 
 func init() {
-	cflareEmail = os.Getenv("CLOUDFLARE_EMAIL")
-	cflareAPIKey = os.Getenv("CLOUDFLARE_API_KEY")
-	cflareDomain = os.Getenv("CLOUDFLARE_DOMAIN")
-	if len(cflareEmail) > 0 && len(cflareAPIKey) > 0 && len(cflareDomain) > 0 {
-		cflareLiveTest = true
+	envTestEmail = os.Getenv("CLOUDFLARE_EMAIL")
+	envTestAPIKey = os.Getenv("CLOUDFLARE_API_KEY")
+	envTestDomain = os.Getenv("CLOUDFLARE_DOMAIN")
+	if len(envTestEmail) > 0 && len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("CLOUDFLARE_EMAIL", cflareEmail)
-	os.Setenv("CLOUDFLARE_API_KEY", cflareAPIKey)
+	os.Setenv("CLOUDFLARE_EMAIL", envTestEmail)
+	os.Setenv("CLOUDFLARE_API_KEY", envTestAPIKey)
 }
 
 func TestNewDNSProvider(t *testing.T) {
@@ -83,8 +83,10 @@ func TestNewDNSProvider(t *testing.T) {
 			p, err := NewDNSProvider()
 
 			if len(test.expected) == 0 {
-				assert.NoError(t, err)
-				assert.NotNil(t, p)
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				assert.NotNil(t, p.config)
+				assert.NotNil(t, p.client)
 			} else {
 				require.EqualError(t, err, test.expected)
 			}
@@ -133,8 +135,10 @@ func TestNewDNSProviderConfig(t *testing.T) {
 			p, err := NewDNSProviderConfig(config)
 
 			if len(test.expected) == 0 {
-				assert.NoError(t, err)
-				assert.NotNil(t, p)
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				assert.NotNil(t, p.config)
+				assert.NotNil(t, p.client)
 			} else {
 				require.EqualError(t, err, test.expected)
 			}
@@ -142,36 +146,36 @@ func TestNewDNSProviderConfig(t *testing.T) {
 	}
 }
 
-func TestCloudFlarePresent(t *testing.T) {
-	if !cflareLiveTest {
+func TestPresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
 	config := NewDefaultConfig()
-	config.AuthEmail = cflareEmail
-	config.AuthKey = cflareAPIKey
+	config.AuthEmail = envTestEmail
+	config.AuthKey = envTestAPIKey
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.Present(cflareDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
-func TestCloudFlareCleanUp(t *testing.T) {
-	if !cflareLiveTest {
+func TestCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
 	time.Sleep(time.Second * 2)
 
 	config := NewDefaultConfig()
-	config.AuthEmail = cflareEmail
-	config.AuthKey = cflareAPIKey
+	config.AuthEmail = envTestEmail
+	config.AuthKey = envTestAPIKey
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.CleanUp(cflareDomain, "", "123d==")
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/cloudxns/cloudxns_test.go b/providers/dns/cloudxns/cloudxns_test.go
index aa1ddf27..83c5d32f 100644
--- a/providers/dns/cloudxns/cloudxns_test.go
+++ b/providers/dns/cloudxns/cloudxns_test.go
@@ -5,79 +5,169 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	cxLiveTest  bool
-	cxAPIKey    string
-	cxSecretKey string
-	cxDomain    string
+	liveTest         bool
+	envTestAPIKey    string
+	envTestSecretKey string
+	envTestDomain    string
 )
 
 func init() {
-	cxAPIKey = os.Getenv("CLOUDXNS_API_KEY")
-	cxSecretKey = os.Getenv("CLOUDXNS_SECRET_KEY")
-	cxDomain = os.Getenv("CLOUDXNS_DOMAIN")
-	if len(cxAPIKey) > 0 && len(cxSecretKey) > 0 && len(cxDomain) > 0 {
-		cxLiveTest = true
+	envTestAPIKey = os.Getenv("CLOUDXNS_API_KEY")
+	envTestSecretKey = os.Getenv("CLOUDXNS_SECRET_KEY")
+	envTestDomain = os.Getenv("CLOUDXNS_DOMAIN")
+
+	if len(envTestAPIKey) > 0 && len(envTestSecretKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("CLOUDXNS_API_KEY", cxAPIKey)
-	os.Setenv("CLOUDXNS_SECRET_KEY", cxSecretKey)
-}
-
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("CLOUDXNS_API_KEY", "")
-	os.Setenv("CLOUDXNS_SECRET_KEY", "")
-
-	_, err := NewDNSProviderCredentials("123", "123")
-	assert.NoError(t, err)
+	os.Setenv("CLOUDXNS_API_KEY", envTestAPIKey)
+	os.Setenv("CLOUDXNS_SECRET_KEY", envTestSecretKey)
 }
 
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("CLOUDXNS_API_KEY", "123")
-	os.Setenv("CLOUDXNS_SECRET_KEY", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"CLOUDXNS_API_KEY":    "123",
+				"CLOUDXNS_SECRET_KEY": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"CLOUDXNS_API_KEY":    "",
+				"CLOUDXNS_SECRET_KEY": "",
+			},
+			expected: "CloudXNS: some credentials information are missing: CLOUDXNS_API_KEY,CLOUDXNS_SECRET_KEY",
+		},
+		{
+			desc: "missing API key",
+			envVars: map[string]string{
+				"CLOUDXNS_API_KEY":    "",
+				"CLOUDXNS_SECRET_KEY": "456",
+			},
+			expected: "CloudXNS: some credentials information are missing: CLOUDXNS_API_KEY",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"CLOUDXNS_API_KEY":    "123",
+				"CLOUDXNS_SECRET_KEY": "",
+			},
+			expected: "CloudXNS: some credentials information are missing: CLOUDXNS_SECRET_KEY",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("CLOUDXNS_API_KEY", "")
-	os.Setenv("CLOUDXNS_SECRET_KEY", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		apiKey    string
+		secretKey string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			apiKey:    "123",
+			secretKey: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "CloudXNS: credentials missing: apiKey",
+		},
+		{
+			desc:      "missing api key",
+			secretKey: "456",
+			expected:  "CloudXNS: credentials missing: apiKey",
+		},
+		{
+			desc:     "missing secret key",
+			apiKey:   "123",
+			expected: "CloudXNS: credentials missing: secretKey",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "CloudXNS: some credentials information are missing: CLOUDXNS_API_KEY,CLOUDXNS_SECRET_KEY")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("CLOUDXNS_API_KEY")
+			os.Unsetenv("CLOUDXNS_SECRET_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.SecretKey = test.secretKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestCloudXNSPresent(t *testing.T) {
-	if !cxLiveTest {
+func TestPresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	provider, err := NewDNSProviderCredentials(cxAPIKey, cxSecretKey)
-	assert.NoError(t, err)
+	provider, err := NewDNSProviderCredentials(envTestAPIKey, envTestSecretKey)
+	require.NoError(t, err)
 
-	err = provider.Present(cxDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestCloudXNSCleanUp(t *testing.T) {
-	if !cxLiveTest {
+func TestCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
 	time.Sleep(time.Second * 2)
 
-	provider, err := NewDNSProviderCredentials(cxAPIKey, cxSecretKey)
-	assert.NoError(t, err)
+	provider, err := NewDNSProviderCredentials(envTestAPIKey, envTestSecretKey)
+	require.NoError(t, err)
 
-	err = provider.CleanUp(cxDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/digitalocean/digitalocean_test.go b/providers/dns/digitalocean/digitalocean_test.go
index 49a1be92..89005de1 100644
--- a/providers/dns/digitalocean/digitalocean_test.go
+++ b/providers/dns/digitalocean/digitalocean_test.go
@@ -5,31 +5,146 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
-var fakeDigitalOceanAuth = "asdf1234"
+var (
+	envTestAuthToken string
+)
+
+func init() {
+	envTestAuthToken = os.Getenv("DO_AUTH_TOKEN")
+}
+
+func restoreEnv() {
+	os.Setenv("DO_AUTH_TOKEN", envTestAuthToken)
+}
+
+func setupTest() (*DNSProvider, *http.ServeMux, func()) {
+	handler := http.NewServeMux()
+	server := httptest.NewServer(handler)
+
+	config := NewDefaultConfig()
+	config.AuthToken = "asdf1234"
+	config.BaseURL = server.URL
+
+	provider, err := NewDNSProviderConfig(config)
+	if err != nil {
+		panic(err)
+	}
+
+	return provider, handler, server.Close
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"DO_AUTH_TOKEN": "123",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"DO_AUTH_TOKEN": "",
+			},
+			expected: "digitalocean: some credentials information are missing: DO_AUTH_TOKEN",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.recordIDs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
 
-func TestDigitalOceanPresent(t *testing.T) {
-	var requestReceived bool
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		authToken string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			authToken: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "digitalocean: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("DO_AUTH_TOKEN")
+			os.Unsetenv("ALICLOUD_SECRET_KEY")
+
+			config := NewDefaultConfig()
+			config.AuthToken = test.authToken
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.recordIDs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
 
-	mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		requestReceived = true
+func TestDNSProvider_Present(t *testing.T) {
+	provider, mux, tearDown := setupTest()
+	defer tearDown()
 
+	mux.HandleFunc("/v2/domains/example.com/records", func(w http.ResponseWriter, r *http.Request) {
 		assert.Equal(t, http.MethodPost, r.Method, "method")
-		assert.Equal(t, "/v2/domains/example.com/records", r.URL.Path, "Path")
+
 		assert.Equal(t, "application/json", r.Header.Get("Content-Type"), "Content-Type")
 		assert.Equal(t, "Bearer asdf1234", r.Header.Get("Authorization"), "Authorization")
 
 		reqBody, err := ioutil.ReadAll(r.Body)
-		require.NoError(t, err, "reading request body")
-		assert.Equal(t, `{"type":"TXT","name":"_acme-challenge.example.com.","data":"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI","ttl":30}`, string(reqBody))
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+		}
+
+		expectedReqBody := `{"type":"TXT","name":"_acme-challenge.example.com.","data":"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI","ttl":30}`
+		assert.Equal(t, expectedReqBody, string(reqBody))
 
 		w.WriteHeader(http.StatusCreated)
-		fmt.Fprintf(w, `{
+		_, err = fmt.Fprintf(w, `{
 			"domain_record": {
 				"id": 1234567,
 				"type": "TXT",
@@ -40,53 +155,35 @@ func TestDigitalOceanPresent(t *testing.T) {
 				"weight": null
 			}
 		}`)
-	}))
-	defer mock.Close()
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+		}
+	})
 
-	config := NewDefaultConfig()
-	config.AuthToken = fakeDigitalOceanAuth
-	config.BaseURL = mock.URL
-
-	provider, err := NewDNSProviderConfig(config)
+	err := provider.Present("example.com", "", "foobar")
 	require.NoError(t, err)
-	require.NotNil(t, provider)
-
-	err = provider.Present("example.com", "", "foobar")
-	require.NoError(t, err, "fail to create TXT record")
-
-	assert.True(t, requestReceived, "Expected request to be received by mock backend, but it wasn't")
 }
 
-func TestDigitalOceanCleanUp(t *testing.T) {
-	var requestReceived bool
-
-	mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		requestReceived = true
+func TestDNSProvider_CleanUp(t *testing.T) {
+	provider, mux, tearDown := setupTest()
+	defer tearDown()
 
+	mux.HandleFunc("/v2/domains/example.com/records/1234567", func(w http.ResponseWriter, r *http.Request) {
 		assert.Equal(t, http.MethodDelete, r.Method, "method")
+
 		assert.Equal(t, "/v2/domains/example.com/records/1234567", r.URL.Path, "Path")
+
 		// NOTE: Even though the body is empty, DigitalOcean API docs still show setting this Content-Type...
 		assert.Equal(t, "application/json", r.Header.Get("Content-Type"), "Content-Type")
 		assert.Equal(t, "Bearer asdf1234", r.Header.Get("Authorization"), "Authorization")
 
 		w.WriteHeader(http.StatusNoContent)
-	}))
-	defer mock.Close()
-
-	config := NewDefaultConfig()
-	config.AuthToken = fakeDigitalOceanAuth
-	config.BaseURL = mock.URL
-
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-	require.NotNil(t, provider)
+	})
 
 	provider.recordIDsMu.Lock()
 	provider.recordIDs["_acme-challenge.example.com."] = 1234567
 	provider.recordIDsMu.Unlock()
 
-	err = provider.CleanUp("example.com", "", "")
+	err := provider.CleanUp("example.com", "", "")
 	require.NoError(t, err, "fail to remove TXT record")
-
-	assert.True(t, requestReceived, "Expected request to be received by mock backend, but it wasn't")
 }
diff --git a/providers/dns/dns_providers_test.go b/providers/dns/dns_providers_test.go
index 29c366c8..c953a2b2 100644
--- a/providers/dns/dns_providers_test.go
+++ b/providers/dns/dns_providers_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/xenolf/lego/providers/dns/exoscale"
 )
 
@@ -29,7 +30,7 @@ func TestKnownDNSProviderSuccess(t *testing.T) {
 	os.Setenv("EXOSCALE_API_SECRET", "123")
 
 	provider, err := NewDNSChallengeProviderByName("exoscale")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	assert.NotNil(t, provider)
 
 	assert.IsType(t, &exoscale.DNSProvider{}, provider, "Not loaded correct DNS provider")
diff --git a/providers/dns/dnsimple/dnsimple_test.go b/providers/dns/dnsimple/dnsimple_test.go
index 652a1832..e5adaac2 100644
--- a/providers/dns/dnsimple/dnsimple_test.go
+++ b/providers/dns/dnsimple/dnsimple_test.go
@@ -11,31 +11,31 @@ import (
 )
 
 var (
-	dnsimpleLiveTest   bool
-	dnsimpleOauthToken string
-	dnsimpleDomain     string
-	dnsimpleBaseURL    string
+	liveTest          bool
+	envTestOauthToken string
+	envTestDomain     string
+	envTestBaseURL    string
 )
 
 func init() {
-	dnsimpleOauthToken = os.Getenv("DNSIMPLE_OAUTH_TOKEN")
-	dnsimpleDomain = os.Getenv("DNSIMPLE_DOMAIN")
-	dnsimpleBaseURL = "https://api.sandbox.dnsimple.com"
+	envTestOauthToken = os.Getenv("DNSIMPLE_OAUTH_TOKEN")
+	envTestDomain = os.Getenv("DNSIMPLE_DOMAIN")
+	envTestBaseURL = "https://api.sandbox.fake.com"
 
-	if len(dnsimpleOauthToken) > 0 && len(dnsimpleDomain) > 0 {
+	if len(envTestOauthToken) > 0 && len(envTestDomain) > 0 {
 		baseURL := os.Getenv("DNSIMPLE_BASE_URL")
 
 		if baseURL != "" {
-			dnsimpleBaseURL = baseURL
+			envTestBaseURL = baseURL
 		}
 
-		dnsimpleLiveTest = true
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("DNSIMPLE_OAUTH_TOKEN", dnsimpleOauthToken)
-	os.Setenv("DNSIMPLE_BASE_URL", dnsimpleBaseURL)
+	os.Setenv("DNSIMPLE_OAUTH_TOKEN", envTestOauthToken)
+	os.Setenv("DNSIMPLE_BASE_URL", envTestBaseURL)
 }
 
 func TestNewDNSProvider(t *testing.T) {
@@ -159,44 +159,30 @@ func TestNewDNSProviderConfig(t *testing.T) {
 	}
 }
 
-//
-// Present
-//
-
-func TestLiveDNSimplePresent(t *testing.T) {
-	if !dnsimpleLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.AccessToken = dnsimpleOauthToken
-	config.BaseURL = dnsimpleBaseURL
-
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	err = provider.Present(dnsimpleDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-//
-// Cleanup
-//
-
-func TestLiveDNSimpleCleanUp(t *testing.T) {
-	if !dnsimpleLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
-	config := NewDefaultConfig()
-	config.AccessToken = dnsimpleOauthToken
-	config.BaseURL = dnsimpleBaseURL
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	time.Sleep(1 * time.Second)
 
-	err = provider.CleanUp(dnsimpleDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go b/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go
index 8d6e27ac..5217a83c 100644
--- a/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go
+++ b/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go
@@ -4,35 +4,159 @@ import (
 	"os"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	testLive      bool
-	testAPIKey    string
-	testAPISecret string
-	testDomain    string
+	liveTest         bool
+	envTestAPIKey    string
+	envTestAPISecret string
+	envTestDomain    string
 )
 
 func init() {
-	testAPIKey = os.Getenv("DNSMADEEASY_API_KEY")
-	testAPISecret = os.Getenv("DNSMADEEASY_API_SECRET")
-	testDomain = os.Getenv("DNSMADEEASY_DOMAIN")
+	envTestAPIKey = os.Getenv("DNSMADEEASY_API_KEY")
+	envTestAPISecret = os.Getenv("DNSMADEEASY_API_SECRET")
+	envTestDomain = os.Getenv("DNSMADEEASY_DOMAIN")
+
 	os.Setenv("DNSMADEEASY_SANDBOX", "true")
-	testLive = len(testAPIKey) > 0 && len(testAPISecret) > 0
+
+	liveTest = len(envTestAPIKey) > 0 && len(envTestAPISecret) > 0
+}
+
+func restoreEnv() {
+	os.Setenv("DNSMADEEASY_API_KEY", envTestAPIKey)
+	os.Setenv("DNSMADEEASY_API_SECRET", envTestAPISecret)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"DNSMADEEASY_API_KEY":    "123",
+				"DNSMADEEASY_API_SECRET": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"DNSMADEEASY_API_KEY":    "",
+				"DNSMADEEASY_API_SECRET": "",
+			},
+			expected: "dnsmadeeasy: some credentials information are missing: DNSMADEEASY_API_KEY,DNSMADEEASY_API_SECRET",
+		},
+		{
+			desc: "missing access key",
+			envVars: map[string]string{
+				"DNSMADEEASY_API_KEY":    "",
+				"DNSMADEEASY_API_SECRET": "456",
+			},
+			expected: "dnsmadeeasy: some credentials information are missing: DNSMADEEASY_API_KEY",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"DNSMADEEASY_API_KEY":    "123",
+				"DNSMADEEASY_API_SECRET": "",
+			},
+			expected: "dnsmadeeasy: some credentials information are missing: DNSMADEEASY_API_SECRET",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		apiKey    string
+		apiSecret string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			apiKey:    "123",
+			apiSecret: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "dnsmadeeasy: credentials missing: API key",
+		},
+		{
+			desc:      "missing api key",
+			apiSecret: "456",
+			expected:  "dnsmadeeasy: credentials missing: API key",
+		},
+		{
+			desc:     "missing secret key",
+			apiKey:   "123",
+			expected: "dnsmadeeasy: credentials missing: API secret",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("DNSMADEEASY_API_KEY")
+			os.Unsetenv("DNSMADEEASY_API_SECRET")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.APISecret = test.apiSecret
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestPresentAndCleanup(t *testing.T) {
-	if !testLive {
+func TestLivePresentAndCleanup(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.Present(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 
-	err = provider.CleanUp(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/dnspod/dnspod_test.go b/providers/dns/dnspod/dnspod_test.go
index 95fac006..8108ac21 100644
--- a/providers/dns/dnspod/dnspod_test.go
+++ b/providers/dns/dnspod/dnspod_test.go
@@ -5,81 +5,136 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	dnspodLiveTest bool
-	dnspodAPIKey   string
-	dnspodDomain   string
+	liveTest      bool
+	envTestAPIKey string
+	envTestDomain string
 )
 
 func init() {
-	dnspodAPIKey = os.Getenv("DNSPOD_API_KEY")
-	dnspodDomain = os.Getenv("DNSPOD_DOMAIN")
-	if len(dnspodAPIKey) > 0 && len(dnspodDomain) > 0 {
-		dnspodLiveTest = true
+	envTestAPIKey = os.Getenv("DNSPOD_API_KEY")
+	envTestDomain = os.Getenv("DNSPOD_DOMAIN")
+
+	if len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("DNSPOD_API_KEY", dnspodAPIKey)
+	os.Setenv("DNSPOD_API_KEY", envTestAPIKey)
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("DNSPOD_API_KEY", "")
-
-	config := NewDefaultConfig()
-	config.LoginToken = "123"
-
-	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-}
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("DNSPOD_API_KEY", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"DNSPOD_API_KEY": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"DNSPOD_API_KEY": "",
+			},
+			expected: "dnspod: some credentials information are missing: DNSPOD_API_KEY",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("DNSPOD_API_KEY", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc       string
+		loginToken string
+		expected   string
+	}{
+		{
+			desc:       "success",
+			loginToken: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "dnspod: credentials missing",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "dnspod: some credentials information are missing: DNSPOD_API_KEY")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("DNSPOD_API_KEY")
+
+			config := NewDefaultConfig()
+			config.LoginToken = test.loginToken
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestLivednspodPresent(t *testing.T) {
-	if !dnspodLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.LoginToken = dnspodAPIKey
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-
-	err = provider.Present(dnspodDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestLivednspodCleanUp(t *testing.T) {
-	if !dnspodLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
-	config := NewDefaultConfig()
-	config.LoginToken = dnspodAPIKey
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	time.Sleep(1 * time.Second)
 
-	err = provider.CleanUp(dnspodDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/duckdns/duckdns_test.go b/providers/dns/duckdns/duckdns_test.go
index a078a26d..d2aac729 100644
--- a/providers/dns/duckdns/duckdns_test.go
+++ b/providers/dns/duckdns/duckdns_test.go
@@ -5,65 +5,133 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	duckdnsLiveTest bool
-	duckdnsToken    string
-	duckdnsDomain   string
+	liveTest      bool
+	envTestToken  string
+	envTestDomain string
 )
 
 func init() {
-	duckdnsToken = os.Getenv("DUCKDNS_TOKEN")
-	duckdnsDomain = os.Getenv("DUCKDNS_DOMAIN")
-	if len(duckdnsToken) > 0 && len(duckdnsDomain) > 0 {
-		duckdnsLiveTest = true
+	envTestToken = os.Getenv("DUCKDNS_TOKEN")
+	envTestDomain = os.Getenv("DUCKDNS_DOMAIN")
+	if len(envTestToken) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("DUCKDNS_TOKEN", duckdnsToken)
+	os.Setenv("DUCKDNS_TOKEN", envTestToken)
 }
 
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("DUCKDNS_TOKEN", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"DUCKDNS_TOKEN": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"DUCKDNS_TOKEN": "",
+			},
+			expected: "duckdns: some credentials information are missing: DUCKDNS_TOKEN",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("DUCKDNS_TOKEN", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		token    string
+		expected string
+	}{
+		{
+			desc:  "success",
+			token: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "duckdns: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("DUCKDNS_TOKEN")
+
+			config := NewDefaultConfig()
+			config.Token = test.token
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "duckdns: some credentials information are missing: DUCKDNS_TOKEN")
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestLiveDuckdnsPresent(t *testing.T) {
-	if !duckdnsLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.Present(duckdnsDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestLiveDuckdnsCleanUp(t *testing.T) {
-	if !duckdnsLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 10)
-
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
+
+	time.Sleep(10 * time.Second)
 
-	err = provider.CleanUp(duckdnsDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/dyn/dyn_test.go b/providers/dns/dyn/dyn_test.go
index 5bbca10c..47cf8f83 100644
--- a/providers/dns/dyn/dyn_test.go
+++ b/providers/dns/dyn/dyn_test.go
@@ -5,50 +5,198 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 var (
-	dynLiveTest     bool
-	dynCustomerName string
-	dynUserName     string
-	dynPassword     string
-	dynDomain       string
+	liveTest            bool
+	envTestCustomerName string
+	envTestUserName     string
+	envTestPassword     string
+	envTestDomain       string
 )
 
 func init() {
-	dynCustomerName = os.Getenv("DYN_CUSTOMER_NAME")
-	dynUserName = os.Getenv("DYN_USER_NAME")
-	dynPassword = os.Getenv("DYN_PASSWORD")
-	dynDomain = os.Getenv("DYN_DOMAIN")
-	if len(dynCustomerName) > 0 && len(dynUserName) > 0 && len(dynPassword) > 0 && len(dynDomain) > 0 {
-		dynLiveTest = true
+	envTestCustomerName = os.Getenv("DYN_CUSTOMER_NAME")
+	envTestUserName = os.Getenv("DYN_USER_NAME")
+	envTestPassword = os.Getenv("DYN_PASSWORD")
+	envTestDomain = os.Getenv("DYN_DOMAIN")
+
+	if len(envTestCustomerName) > 0 && len(envTestUserName) > 0 && len(envTestPassword) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
+	}
+}
+
+func restoreEnv() {
+	os.Setenv("DYN_CUSTOMER_NAME", envTestCustomerName)
+	os.Setenv("DYN_USER_NAME", envTestUserName)
+	os.Setenv("DYN_PASSWORD", envTestPassword)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"DYN_CUSTOMER_NAME": "A",
+				"DYN_USER_NAME":     "B",
+				"DYN_PASSWORD":      "C",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"DYN_CUSTOMER_NAME": "",
+				"DYN_USER_NAME":     "",
+				"DYN_PASSWORD":      "",
+			},
+			expected: "dyn: some credentials information are missing: DYN_CUSTOMER_NAME,DYN_USER_NAME,DYN_PASSWORD",
+		},
+		{
+			desc: "missing customer name",
+			envVars: map[string]string{
+				"DYN_CUSTOMER_NAME": "",
+				"DYN_USER_NAME":     "B",
+				"DYN_PASSWORD":      "C",
+			},
+			expected: "dyn: some credentials information are missing: DYN_CUSTOMER_NAME",
+		},
+		{
+			desc: "missing password",
+			envVars: map[string]string{
+				"DYN_CUSTOMER_NAME": "A",
+				"DYN_USER_NAME":     "",
+				"DYN_PASSWORD":      "C",
+			},
+			expected: "dyn: some credentials information are missing: DYN_USER_NAME",
+		},
+		{
+			desc: "missing username",
+			envVars: map[string]string{
+				"DYN_CUSTOMER_NAME": "A",
+				"DYN_USER_NAME":     "B",
+				"DYN_PASSWORD":      "",
+			},
+			expected: "dyn: some credentials information are missing: DYN_PASSWORD",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
 	}
 }
 
-func TestLiveDynPresent(t *testing.T) {
-	if !dynLiveTest {
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc         string
+		customerName string
+		password     string
+		userName     string
+		expected     string
+	}{
+		{
+			desc:         "success",
+			customerName: "A",
+			password:     "B",
+			userName:     "C",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "dyn: credentials missing",
+		},
+		{
+			desc:         "missing customer name",
+			customerName: "",
+			password:     "B",
+			userName:     "C",
+			expected:     "dyn: credentials missing",
+		},
+		{
+			desc:         "missing password",
+			customerName: "A",
+			password:     "",
+			userName:     "C",
+			expected:     "dyn: credentials missing",
+		},
+		{
+			desc:         "missing username",
+			customerName: "A",
+			password:     "B",
+			userName:     "",
+			expected:     "dyn: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("DNSPOD_API_KEY")
+
+			config := NewDefaultConfig()
+			config.CustomerName = test.customerName
+			config.Password = test.password
+			config.UserName = test.userName
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(dynDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestLiveDynCleanUp(t *testing.T) {
-	if !dynLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.CleanUp(dynDomain, "", "123d==")
-	assert.NoError(t, err)
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/exoscale/exoscale_test.go b/providers/dns/exoscale/exoscale_test.go
index 0dacc653..84056e72 100644
--- a/providers/dns/exoscale/exoscale_test.go
+++ b/providers/dns/exoscale/exoscale_test.go
@@ -10,55 +10,141 @@ import (
 )
 
 var (
-	exoscaleLiveTest  bool
-	exoscaleAPIKey    string
-	exoscaleAPISecret string
-	exoscaleDomain    string
+	liveTest         bool
+	envTestAPIKey    string
+	envTestAPISecret string
+	envTestDomain    string
 )
 
 func init() {
-	exoscaleAPISecret = os.Getenv("EXOSCALE_API_SECRET")
-	exoscaleAPIKey = os.Getenv("EXOSCALE_API_KEY")
-	exoscaleDomain = os.Getenv("EXOSCALE_DOMAIN")
-	if len(exoscaleAPIKey) > 0 && len(exoscaleAPISecret) > 0 && len(exoscaleDomain) > 0 {
-		exoscaleLiveTest = true
+	envTestAPISecret = os.Getenv("EXOSCALE_API_SECRET")
+	envTestAPIKey = os.Getenv("EXOSCALE_API_KEY")
+	envTestDomain = os.Getenv("EXOSCALE_DOMAIN")
+
+	if len(envTestAPIKey) > 0 && len(envTestAPISecret) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("EXOSCALE_API_KEY", exoscaleAPIKey)
-	os.Setenv("EXOSCALE_API_SECRET", exoscaleAPISecret)
-}
-
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("EXOSCALE_API_KEY", "")
-	os.Setenv("EXOSCALE_API_SECRET", "")
-
-	config := NewDefaultConfig()
-	config.APIKey = "example@example.com"
-	config.APISecret = "123"
-
-	_, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
+	os.Setenv("EXOSCALE_API_KEY", envTestAPIKey)
+	os.Setenv("EXOSCALE_API_SECRET", envTestAPISecret)
 }
 
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("EXOSCALE_API_KEY", "example@example.com")
-	os.Setenv("EXOSCALE_API_SECRET", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"EXOSCALE_API_KEY":    "123",
+				"EXOSCALE_API_SECRET": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"EXOSCALE_API_KEY":    "",
+				"EXOSCALE_API_SECRET": "",
+			},
+			expected: "exoscale: some credentials information are missing: EXOSCALE_API_KEY,EXOSCALE_API_SECRET",
+		},
+		{
+			desc: "missing access key",
+			envVars: map[string]string{
+				"EXOSCALE_API_KEY":    "",
+				"EXOSCALE_API_SECRET": "456",
+			},
+			expected: "exoscale: some credentials information are missing: EXOSCALE_API_KEY",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"EXOSCALE_API_KEY":    "123",
+				"EXOSCALE_API_SECRET": "",
+			},
+			expected: "exoscale: some credentials information are missing: EXOSCALE_API_SECRET",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	os.Setenv("EXOSCALE_API_KEY", "")
-	os.Setenv("EXOSCALE_API_SECRET", "")
-	defer restoreEnv()
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		apiKey    string
+		apiSecret string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			apiKey:    "123",
+			apiSecret: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "exoscale: credentials missing",
+		},
+		{
+			desc:      "missing api key",
+			apiSecret: "456",
+			expected:  "exoscale: credentials missing",
+		},
+		{
+			desc:     "missing secret key",
+			apiKey:   "123",
+			expected: "exoscale: credentials missing",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "exoscale: some credentials information are missing: EXOSCALE_API_KEY,EXOSCALE_API_SECRET")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("EXOSCALE_API_KEY")
+			os.Unsetenv("EXOSCALE_API_SECRET")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.APISecret = test.apiSecret
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func TestDNSProvider_FindZoneAndRecordName(t *testing.T) {
@@ -113,40 +199,34 @@ func TestDNSProvider_FindZoneAndRecordName(t *testing.T) {
 	}
 }
 
-func TestLiveExoscalePresent(t *testing.T) {
-	if !exoscaleLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.APIKey = exoscaleAPIKey
-	config.APISecret = exoscaleAPISecret
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(exoscaleDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 
 	// Present Twice to handle create / update
-	err = provider.Present(exoscaleDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
-func TestLiveExoscaleCleanUp(t *testing.T) {
-	if !exoscaleLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
-	config := NewDefaultConfig()
-	config.APIKey = exoscaleAPIKey
-	config.APISecret = exoscaleAPISecret
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(exoscaleDomain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/fastdns/fastdns_test.go b/providers/dns/fastdns/fastdns_test.go
index abd21236..30ff9aa0 100644
--- a/providers/dns/fastdns/fastdns_test.go
+++ b/providers/dns/fastdns/fastdns_test.go
@@ -10,92 +10,203 @@ import (
 )
 
 var (
-	fastdnsLiveTest bool
-	host            string
-	clientToken     string
-	clientSecret    string
-	accessToken     string
-	testDomain      string
+	liveTest            bool
+	envTestHost         string
+	envTestClientToken  string
+	envTestClientSecret string
+	envTestAccessToken  string
+	envTestDomain       string
 )
 
 func init() {
-	host = os.Getenv("AKAMAI_HOST")
-	clientToken = os.Getenv("AKAMAI_CLIENT_TOKEN")
-	clientSecret = os.Getenv("AKAMAI_CLIENT_SECRET")
-	accessToken = os.Getenv("AKAMAI_ACCESS_TOKEN")
-	testDomain = os.Getenv("AKAMAI_TEST_DOMAIN")
-
-	if len(host) > 0 && len(clientToken) > 0 && len(clientSecret) > 0 && len(accessToken) > 0 {
-		fastdnsLiveTest = true
+	envTestHost = os.Getenv("AKAMAI_HOST")
+	envTestClientToken = os.Getenv("AKAMAI_CLIENT_TOKEN")
+	envTestClientSecret = os.Getenv("AKAMAI_CLIENT_SECRET")
+	envTestAccessToken = os.Getenv("AKAMAI_ACCESS_TOKEN")
+	envTestDomain = os.Getenv("AKAMAI_TEST_DOMAIN")
+
+	if len(envTestHost) > 0 && len(envTestClientToken) > 0 && len(envTestClientSecret) > 0 && len(envTestAccessToken) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("AKAMAI_HOST", host)
-	os.Setenv("AKAMAI_CLIENT_TOKEN", clientToken)
-	os.Setenv("AKAMAI_CLIENT_SECRET", clientSecret)
-	os.Setenv("AKAMAI_ACCESS_TOKEN", accessToken)
+	os.Setenv("AKAMAI_HOST", envTestHost)
+	os.Setenv("AKAMAI_CLIENT_TOKEN", envTestClientToken)
+	os.Setenv("AKAMAI_CLIENT_SECRET", envTestClientSecret)
+	os.Setenv("AKAMAI_ACCESS_TOKEN", envTestAccessToken)
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("AKAMAI_HOST", "")
-	os.Setenv("AKAMAI_CLIENT_TOKEN", "")
-	os.Setenv("AKAMAI_CLIENT_SECRET", "")
-	os.Setenv("AKAMAI_ACCESS_TOKEN", "")
-
-	config := NewDefaultConfig()
-	config.Host = "somehost"
-	config.ClientToken = "someclienttoken"
-	config.ClientSecret = "someclientsecret"
-	config.AccessToken = "someaccesstoken"
-
-	_, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-}
-
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("AKAMAI_HOST", "somehost")
-	os.Setenv("AKAMAI_CLIENT_TOKEN", "someclienttoken")
-	os.Setenv("AKAMAI_CLIENT_SECRET", "someclientsecret")
-	os.Setenv("AKAMAI_ACCESS_TOKEN", "someaccesstoken")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"AKAMAI_HOST":          "A",
+				"AKAMAI_CLIENT_TOKEN":  "B",
+				"AKAMAI_CLIENT_SECRET": "C",
+				"AKAMAI_ACCESS_TOKEN":  "D",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"AKAMAI_HOST":          "",
+				"AKAMAI_CLIENT_TOKEN":  "",
+				"AKAMAI_CLIENT_SECRET": "",
+				"AKAMAI_ACCESS_TOKEN":  "",
+			},
+			expected: "fastdns: some credentials information are missing: AKAMAI_HOST,AKAMAI_CLIENT_TOKEN,AKAMAI_CLIENT_SECRET,AKAMAI_ACCESS_TOKEN",
+		},
+		{
+			desc: "missing host",
+			envVars: map[string]string{
+				"AKAMAI_HOST":          "",
+				"AKAMAI_CLIENT_TOKEN":  "B",
+				"AKAMAI_CLIENT_SECRET": "C",
+				"AKAMAI_ACCESS_TOKEN":  "D",
+			},
+			expected: "fastdns: some credentials information are missing: AKAMAI_HOST",
+		},
+		{
+			desc: "missing client token",
+			envVars: map[string]string{
+				"AKAMAI_HOST":          "A",
+				"AKAMAI_CLIENT_TOKEN":  "",
+				"AKAMAI_CLIENT_SECRET": "C",
+				"AKAMAI_ACCESS_TOKEN":  "D",
+			},
+			expected: "fastdns: some credentials information are missing: AKAMAI_CLIENT_TOKEN",
+		},
+		{
+			desc: "missing client secret",
+			envVars: map[string]string{
+				"AKAMAI_HOST":          "A",
+				"AKAMAI_CLIENT_TOKEN":  "B",
+				"AKAMAI_CLIENT_SECRET": "",
+				"AKAMAI_ACCESS_TOKEN":  "D",
+			},
+			expected: "fastdns: some credentials information are missing: AKAMAI_CLIENT_SECRET",
+		},
+		{
+			desc: "missing access token",
+			envVars: map[string]string{
+				"AKAMAI_HOST":          "A",
+				"AKAMAI_CLIENT_TOKEN":  "B",
+				"AKAMAI_CLIENT_SECRET": "C",
+				"AKAMAI_ACCESS_TOKEN":  "",
+			},
+			expected: "fastdns: some credentials information are missing: AKAMAI_ACCESS_TOKEN",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
-}
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("AKAMAI_HOST", "")
-	os.Setenv("AKAMAI_CLIENT_TOKEN", "")
-	os.Setenv("AKAMAI_CLIENT_SECRET", "")
-	os.Setenv("AKAMAI_ACCESS_TOKEN", "")
+			p, err := NewDNSProvider()
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "fastdns: some credentials information are missing: AKAMAI_HOST,AKAMAI_CLIENT_TOKEN,AKAMAI_CLIENT_SECRET,AKAMAI_ACCESS_TOKEN")
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestLiveFastdnsPresent(t *testing.T) {
-	if !fastdnsLiveTest {
-		t.Skip("skipping live test")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc         string
+		host         string
+		clientToken  string
+		clientSecret string
+		accessToken  string
+		expected     string
+	}{
+		{
+			desc:         "success",
+			host:         "A",
+			clientToken:  "B",
+			clientSecret: "C",
+			accessToken:  "D",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "fastdns: credentials are missing",
+		},
+		{
+			desc:         "missing host",
+			host:         "",
+			clientToken:  "B",
+			clientSecret: "C",
+			accessToken:  "D",
+			expected:     "fastdns: credentials are missing",
+		},
+		{
+			desc:         "missing client token",
+			host:         "A",
+			clientToken:  "",
+			clientSecret: "C",
+			accessToken:  "D",
+			expected:     "fastdns: credentials are missing",
+		},
+		{
+			desc:         "missing client secret",
+			host:         "A",
+			clientToken:  "B",
+			clientSecret: "",
+			accessToken:  "B",
+			expected:     "fastdns: credentials are missing",
+		},
+		{
+			desc:         "missing access token",
+			host:         "A",
+			clientToken:  "B",
+			clientSecret: "C",
+			accessToken:  "",
+			expected:     "fastdns: credentials are missing",
+		},
 	}
 
-	config := NewDefaultConfig()
-	config.Host = host
-	config.ClientToken = clientToken
-	config.ClientSecret = clientSecret
-	config.AccessToken = accessToken
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("AKAMAI_HOST")
+			os.Unsetenv("AKAMAI_CLIENT_TOKEN")
+			os.Unsetenv("AKAMAI_CLIENT_SECRET")
+			os.Unsetenv("AKAMAI_ACCESS_TOKEN")
 
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
+			config := NewDefaultConfig()
+			config.ClientToken = test.clientToken
+			config.ClientSecret = test.clientSecret
+			config.Host = test.host
+			config.AccessToken = test.accessToken
 
-	err = provider.Present(testDomain, "", "123d==")
-	require.NoError(t, err)
+			p, err := NewDNSProviderConfig(config)
 
-	// Present Twice to handle create / update
-	err = provider.Present(testDomain, "", "123d==")
-	require.NoError(t, err)
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func TestDNSProvider_findZoneAndRecordName(t *testing.T) {
@@ -152,22 +263,39 @@ func TestDNSProvider_findZoneAndRecordName(t *testing.T) {
 	}
 }
 
-func TestLiveFastdnsCleanUp(t *testing.T) {
-	if !fastdnsLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
+	}
+
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
+
+	// Present Twice to handle create / update
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
+}
+
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
 	time.Sleep(time.Second * 1)
 
 	config := NewDefaultConfig()
-	config.Host = host
-	config.ClientToken = clientToken
-	config.ClientSecret = clientSecret
-	config.AccessToken = accessToken
+	config.Host = envTestHost
+	config.ClientToken = envTestClientToken
+	config.ClientSecret = envTestClientSecret
+	config.AccessToken = envTestAccessToken
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.CleanUp(testDomain, "", "123d==")
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/gandi/gandi_test.go b/providers/dns/gandi/gandi_test.go
index ea416232..cf1779e8 100644
--- a/providers/dns/gandi/gandi_test.go
+++ b/providers/dns/gandi/gandi_test.go
@@ -5,6 +5,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"os"
 	"regexp"
 	"strings"
 	"testing"
@@ -12,6 +13,104 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+var (
+	envTestAPIKey string
+)
+
+func init() {
+	envTestAPIKey = os.Getenv("GANDI_API_KEY")
+}
+
+func restoreEnv() {
+	os.Setenv("GANDI_API_KEY", envTestAPIKey)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"GANDI_API_KEY": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"GANDI_API_KEY": "",
+			},
+			expected: "gandi: some credentials information are missing: GANDI_API_KEY",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.inProgressFQDNs)
+				require.NotNil(t, p.inProgressAuthZones)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "gandi: no API Key given",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("GANDI_API_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.inProgressFQDNs)
+				require.NotNil(t, p.inProgressAuthZones)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
 // TestDNSProvider runs Present and CleanUp against a fake Gandi RPC
 // Server, whose responses are predetermined for particular requests.
 func TestDNSProvider(t *testing.T) {
diff --git a/providers/dns/gandiv5/gandiv5_test.go b/providers/dns/gandiv5/gandiv5_test.go
index 0cc5e825..693a0b82 100644
--- a/providers/dns/gandiv5/gandiv5_test.go
+++ b/providers/dns/gandiv5/gandiv5_test.go
@@ -5,14 +5,110 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"os"
 	"regexp"
 	"testing"
 
+	"github.com/stretchr/testify/require"
 	"github.com/xenolf/lego/log"
+)
 
-	"github.com/stretchr/testify/require"
+var (
+	envTestAPIKey string
 )
 
+func init() {
+	envTestAPIKey = os.Getenv("GANDIV5_API_KEY")
+}
+
+func restoreEnv() {
+	os.Setenv("GANDIV5_API_KEY", envTestAPIKey)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"GANDIV5_API_KEY": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"GANDIV5_API_KEY": "",
+			},
+			expected: "gandi: some credentials information are missing: GANDIV5_API_KEY",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.inProgressFQDNs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "gandiv5: no API Key given",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("GANDIV5_API_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.inProgressFQDNs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
 // TestDNSProvider runs Present and CleanUp against a fake Gandi RPC
 // Server, whose responses are predetermined for particular requests.
 func TestDNSProvider(t *testing.T) {
diff --git a/providers/dns/gcloud/googlecloud_test.go b/providers/dns/gcloud/googlecloud_test.go
index ec94a79d..e374396a 100644
--- a/providers/dns/gcloud/googlecloud_test.go
+++ b/providers/dns/gcloud/googlecloud_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"golang.org/x/net/context"
 	"golang.org/x/oauth2/google"
@@ -13,93 +12,168 @@ import (
 )
 
 var (
-	gcloudLiveTest bool
-	gcloudProject  string
-	gcloudDomain   string
+	liveTest                            bool
+	envTestProject                      string
+	envTestServiceAccountFile           string
+	envTestGoogleApplicationCredentials string
+	envTestDomain                       string
 )
 
 func init() {
-	gcloudProject = os.Getenv("GCE_PROJECT")
-	gcloudDomain = os.Getenv("GCE_DOMAIN")
+	envTestProject = os.Getenv("GCE_PROJECT")
+	envTestServiceAccountFile = os.Getenv("GCE_SERVICE_ACCOUNT_FILE")
+	envTestGoogleApplicationCredentials = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
+	envTestDomain = os.Getenv("GCE_DOMAIN")
+
 	_, err := google.DefaultClient(context.Background(), dns.NdevClouddnsReadwriteScope)
-	if err == nil && len(gcloudProject) > 0 && len(gcloudDomain) > 0 {
-		gcloudLiveTest = true
+	if err == nil && len(envTestProject) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("GCE_PROJECT", gcloudProject)
+	os.Setenv("GCE_PROJECT", envTestProject)
+	os.Setenv("GCE_SERVICE_ACCOUNT_FILE", envTestServiceAccountFile)
+	os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", envTestGoogleApplicationCredentials)
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	if !gcloudLiveTest {
-		t.Skip("skipping live test (requires credentials)")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "invalid credentials",
+			envVars: map[string]string{
+				"GCE_PROJECT":              "123",
+				"GCE_SERVICE_ACCOUNT_FILE": "",
+				// as Travis run on GCE, we have to alter env
+				"GOOGLE_APPLICATION_CREDENTIALS": "not-a-secret-file",
+			},
+			expected: "googlecloud: unable to get Google Cloud client: google: error getting credentials using GOOGLE_APPLICATION_CREDENTIALS environment variable: open not-a-secret-file: no such file or directory",
+		},
+		{
+			desc: "missing project",
+			envVars: map[string]string{
+				"GCE_PROJECT":              "",
+				"GCE_SERVICE_ACCOUNT_FILE": "",
+			},
+			expected: "googlecloud: project name missing",
+		},
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"GCE_PROJECT":              "",
+				"GCE_SERVICE_ACCOUNT_FILE": "fixtures/gce_account_service_file.json",
+			},
+		},
 	}
 
-	defer restoreEnv()
-	os.Setenv("GCE_PROJECT", "")
-
-	_, err := NewDNSProviderCredentials("my-project")
-	require.NoError(t, err)
-}
-
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	if !gcloudLiveTest {
-		t.Skip("skipping live test (requires credentials)")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
 	}
-
-	defer restoreEnv()
-	os.Setenv("GCE_PROJECT", "my-project")
-
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("GCE_PROJECT", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		project  string
+		expected string
+	}{
+		{
+			desc:     "invalid project",
+			project:  "123",
+			expected: "googlecloud: unable to create Google Cloud DNS service: client is nil",
+		},
+		{
+			desc:     "missing project",
+			expected: "googlecloud: unable to create Google Cloud DNS service: client is nil",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "googlecloud: project name missing")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("GCE_PROJECT")
+			os.Unsetenv("GCE_SERVICE_ACCOUNT_FILE")
+
+			config := NewDefaultConfig()
+			config.Project = test.project
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestLiveGoogleCloudPresent(t *testing.T) {
-	if !gcloudLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	provider, err := NewDNSProviderCredentials(gcloudProject)
+	provider, err := NewDNSProviderCredentials(envTestProject)
 	require.NoError(t, err)
 
-	err = provider.Present(gcloudDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
-func TestLiveGoogleCloudPresentMultiple(t *testing.T) {
-	if !gcloudLiveTest {
+func TestLivePresentMultiple(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	provider, err := NewDNSProviderCredentials(gcloudProject)
+	provider, err := NewDNSProviderCredentials(envTestProject)
 	require.NoError(t, err)
 
 	// Check that we're able to create multiple entries
-	err = provider.Present(gcloudDomain, "1", "123d==")
+	err = provider.Present(envTestDomain, "1", "123d==")
 	require.NoError(t, err)
-	err = provider.Present(gcloudDomain, "2", "123d==")
+
+	err = provider.Present(envTestDomain, "2", "123d==")
 	require.NoError(t, err)
 }
 
-func TestLiveGoogleCloudCleanUp(t *testing.T) {
-	if !gcloudLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
-	provider, err := NewDNSProviderCredentials(gcloudProject)
+	provider, err := NewDNSProviderCredentials(envTestProject)
 	require.NoError(t, err)
 
-	err = provider.CleanUp(gcloudDomain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/glesys/glesys_test.go b/providers/dns/glesys/glesys_test.go
index ccb5d5e8..7a0b9971 100644
--- a/providers/dns/glesys/glesys_test.go
+++ b/providers/dns/glesys/glesys_test.go
@@ -4,58 +4,170 @@ import (
 	"os"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 var (
-	glesysAPIUser  string
-	glesysAPIKey   string
-	glesysDomain   string
-	glesysLiveTest bool
+	liveTest       bool
+	envTestAPIUser string
+	envTestAPIKey  string
+	envTestDomain  string
 )
 
 func init() {
-	glesysAPIUser = os.Getenv("GLESYS_API_USER")
-	glesysAPIKey = os.Getenv("GLESYS_API_KEY")
-	glesysDomain = os.Getenv("GLESYS_DOMAIN")
+	envTestAPIUser = os.Getenv("GLESYS_API_USER")
+	envTestAPIKey = os.Getenv("GLESYS_API_KEY")
 
-	if len(glesysAPIUser) > 0 && len(glesysAPIKey) > 0 && len(glesysDomain) > 0 {
-		glesysLiveTest = true
+	if len(envTestAPIUser) > 0 && len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
+func restoreEnv() {
+	os.Setenv("GLESYS_API_USER", envTestAPIUser)
+	os.Setenv("GLESYS_API_KEY", envTestAPIKey)
+}
+
 func TestNewDNSProvider(t *testing.T) {
-	provider, err := NewDNSProvider()
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"GLESYS_API_USER": "A",
+				"GLESYS_API_KEY":  "B",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"GLESYS_API_USER": "",
+				"GLESYS_API_KEY":  "",
+			},
+			expected: "glesys: some credentials information are missing: GLESYS_API_USER,GLESYS_API_KEY",
+		},
+		{
+			desc: "missing api user",
+			envVars: map[string]string{
+				"GLESYS_API_USER": "",
+				"GLESYS_API_KEY":  "B",
+			},
+			expected: "glesys: some credentials information are missing: GLESYS_API_USER",
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"GLESYS_API_USER": "A",
+				"GLESYS_API_KEY":  "",
+			},
+			expected: "glesys: some credentials information are missing: GLESYS_API_KEY",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.activeRecords)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiUser  string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:    "success",
+			apiUser: "A",
+			apiKey:  "B",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "glesys: incomplete credentials provided",
+		},
+		{
+			desc:     "missing api user",
+			apiUser:  "",
+			apiKey:   "B",
+			expected: "glesys: incomplete credentials provided",
+		},
+		{
+			desc:     "missing api key",
+			apiUser:  "A",
+			apiKey:   "",
+			expected: "glesys: incomplete credentials provided",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("GLESYS_API_USER")
+			os.Unsetenv("GLESYS_API_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.APIUser = test.apiUser
+
+			p, err := NewDNSProviderConfig(config)
 
-	if !glesysLiveTest {
-		assert.Error(t, err)
-	} else {
-		assert.NotNil(t, provider)
-		assert.NoError(t, err)
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.activeRecords)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
 	}
 }
 
-func TestDNSProvider_Present(t *testing.T) {
-	if !glesysLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(glesysDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
-func TestDNSProvider_CleanUp(t *testing.T) {
-	if !glesysLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(glesysDomain, "", "123d==")
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/godaddy/godaddy_test.go b/providers/dns/godaddy/godaddy_test.go
index de84d827..d0c5bf2a 100644
--- a/providers/dns/godaddy/godaddy_test.go
+++ b/providers/dns/godaddy/godaddy_test.go
@@ -4,57 +4,167 @@ import (
 	"os"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
-	godaddyAPIKey    string
-	godaddyAPISecret string
-	godaddyDomain    string
-	godaddyLiveTest  bool
+	liveTest         bool
+	envTestAPIKey    string
+	envTestAPISecret string
+	envTestDomain    string
 )
 
 func init() {
-	godaddyAPIKey = os.Getenv("GODADDY_API_KEY")
-	godaddyAPISecret = os.Getenv("GODADDY_API_SECRET")
-	godaddyDomain = os.Getenv("GODADDY_DOMAIN")
+	envTestAPIKey = os.Getenv("GODADDY_API_KEY")
+	envTestAPISecret = os.Getenv("GODADDY_API_SECRET")
+	envTestDomain = os.Getenv("GODADDY_DOMAIN")
 
-	if len(godaddyAPIKey) > 0 && len(godaddyAPISecret) > 0 && len(godaddyDomain) > 0 {
-		godaddyLiveTest = true
+	if len(envTestAPIKey) > 0 && len(envTestAPISecret) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
+func restoreEnv() {
+	os.Setenv("GODADDY_API_KEY", envTestAPIKey)
+	os.Setenv("GODADDY_API_SECRET", envTestAPISecret)
+}
+
 func TestNewDNSProvider(t *testing.T) {
-	provider, err := NewDNSProvider()
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"GODADDY_API_KEY":    "123",
+				"GODADDY_API_SECRET": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"GODADDY_API_KEY":    "",
+				"GODADDY_API_SECRET": "",
+			},
+			expected: "godaddy: some credentials information are missing: GODADDY_API_KEY,GODADDY_API_SECRET",
+		},
+		{
+			desc: "missing access key",
+			envVars: map[string]string{
+				"GODADDY_API_KEY":    "",
+				"GODADDY_API_SECRET": "456",
+			},
+			expected: "godaddy: some credentials information are missing: GODADDY_API_KEY",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"GODADDY_API_KEY":    "123",
+				"GODADDY_API_SECRET": "",
+			},
+			expected: "godaddy: some credentials information are missing: GODADDY_API_SECRET",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		apiKey    string
+		apiSecret string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			apiKey:    "123",
+			apiSecret: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "godaddy: credentials missing",
+		},
+		{
+			desc:      "missing api key",
+			apiSecret: "456",
+			expected:  "godaddy: credentials missing",
+		},
+		{
+			desc:     "missing secret key",
+			apiKey:   "123",
+			expected: "godaddy: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("GODADDY_API_KEY")
+			os.Unsetenv("GODADDY_API_SECRET")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.APISecret = test.apiSecret
+
+			p, err := NewDNSProviderConfig(config)
 
-	if !godaddyLiveTest {
-		assert.Error(t, err)
-	} else {
-		assert.NotNil(t, provider)
-		assert.NoError(t, err)
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
 	}
 }
 
-func TestDNSProvider_Present(t *testing.T) {
-	if !godaddyLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.Present(godaddyDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestDNSProvider_CleanUp(t *testing.T) {
-	if !godaddyLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.CleanUp(godaddyDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/hostingde/hostingde_test.go b/providers/dns/hostingde/hostingde_test.go
index c948c2aa..d1cd9662 100644
--- a/providers/dns/hostingde/hostingde_test.go
+++ b/providers/dns/hostingde/hostingde_test.go
@@ -5,100 +5,170 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 var (
-	hostingdeLiveTest bool
-	hostingdeAPIKey   string
-	hostingdeZone     string
-	hostingdeDomain   string
+	liveTest      bool
+	envTestAPIKey string
+	envTestZone   string
+	envTestDomain string
 )
 
 func init() {
-	hostingdeAPIKey = os.Getenv("HOSTINGDE_API_KEY")
-	hostingdeZone = os.Getenv("HOSTINGDE_ZONE_NAME")
-	hostingdeDomain = os.Getenv("HOSTINGDE_DOMAIN")
-	if len(hostingdeZone) > 0 && len(hostingdeAPIKey) > 0 && len(hostingdeDomain) > 0 {
-		hostingdeLiveTest = true
+	envTestAPIKey = os.Getenv("HOSTINGDE_API_KEY")
+	envTestZone = os.Getenv("HOSTINGDE_ZONE_NAME")
+	envTestDomain = os.Getenv("HOSTINGDE_DOMAIN")
+	if len(envTestZone) > 0 && len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("HOSTINGDE_ZONE_NAME", hostingdeZone)
-	os.Setenv("HOSTINGDE_API_KEY", hostingdeAPIKey)
+	os.Setenv("HOSTINGDE_ZONE_NAME", envTestZone)
+	os.Setenv("HOSTINGDE_API_KEY", envTestAPIKey)
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	os.Setenv("HOSTINGDE_ZONE_NAME", "")
-	os.Setenv("HOSTINGDE_API_KEY", "")
-	defer restoreEnv()
-
-	config := NewDefaultConfig()
-	config.APIKey = "123"
-	config.ZoneName = "example.com"
-
-	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-}
-
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("HOSTINGDE_ZONE_NAME", "example.com")
-	os.Setenv("HOSTINGDE_API_KEY", "123")
-
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
-}
-
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("HOSTINGDE_ZONE_NAME", "")
-	os.Setenv("HOSTINGDE_API_KEY", "")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"HOSTINGDE_API_KEY":   "123",
+				"HOSTINGDE_ZONE_NAME": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"HOSTINGDE_API_KEY":   "",
+				"HOSTINGDE_ZONE_NAME": "",
+			},
+			expected: "hostingde: some credentials information are missing: HOSTINGDE_API_KEY,HOSTINGDE_ZONE_NAME",
+		},
+		{
+			desc: "missing access key",
+			envVars: map[string]string{
+				"HOSTINGDE_API_KEY":   "",
+				"HOSTINGDE_ZONE_NAME": "456",
+			},
+			expected: "hostingde: some credentials information are missing: HOSTINGDE_API_KEY",
+		},
+		{
+			desc: "missing zone name",
+			envVars: map[string]string{
+				"HOSTINGDE_API_KEY":   "123",
+				"HOSTINGDE_ZONE_NAME": "",
+			},
+			expected: "hostingde: some credentials information are missing: HOSTINGDE_ZONE_NAME",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "hostingde: some credentials information are missing: HOSTINGDE_API_KEY,HOSTINGDE_ZONE_NAME")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.recordIDs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErrSingle(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("HOSTINGDE_ZONE_NAME", "example.com")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		zoneName string
+		expected string
+	}{
+		{
+			desc:     "success",
+			apiKey:   "123",
+			zoneName: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "hostingde: API key missing",
+		},
+		{
+			desc:     "missing api key",
+			zoneName: "456",
+			expected: "hostingde: API key missing",
+		},
+		{
+			desc:     "missing zone name",
+			apiKey:   "123",
+			expected: "hostingde: Zone Name missing",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "hostingde: some credentials information are missing: HOSTINGDE_API_KEY")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("HOSTINGDE_API_KEY")
+			os.Unsetenv("HOSTINGDE_ZONE_NAME")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.ZoneName = test.zoneName
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.recordIDs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestHostingdePresent(t *testing.T) {
-	if !hostingdeLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.APIKey = hostingdeZone
-	config.ZoneName = hostingdeAPIKey
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(hostingdeDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestHostingdeCleanUp(t *testing.T) {
-	if !hostingdeLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 2)
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
 
-	config := NewDefaultConfig()
-	config.APIKey = hostingdeZone
-	config.ZoneName = hostingdeAPIKey
+	time.Sleep(2 * time.Second)
 
-	provider, err := NewDNSProviderConfig(config)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
-
-	err = provider.CleanUp(hostingdeDomain, "", "123d==")
-	assert.NoError(t, err)
 }
diff --git a/providers/dns/iij/iij_test.go b/providers/dns/iij/iij_test.go
index 1bcc76c8..76c3fd5b 100644
--- a/providers/dns/iij/iij_test.go
+++ b/providers/dns/iij/iij_test.go
@@ -9,30 +9,173 @@ import (
 )
 
 var (
-	apiAccessKeyEnv  string
-	apiSecretKeyEnv  string
-	doServiceCodeEnv string
-	testDomain       string
-	liveTest         bool
+	liveTest                bool
+	envTestAPIAccessKey     string
+	envTestAPISecretKeyEnv  string
+	envTestDoServiceCodeEnv string
+	envTestDomain           string
 )
 
 func init() {
-	apiAccessKeyEnv = os.Getenv("IIJ_API_ACCESS_KEY")
-	apiSecretKeyEnv = os.Getenv("IIJ_API_SECRET_KEY")
-	doServiceCodeEnv = os.Getenv("IIJ_DO_SERVICE_CODE")
+	envTestAPIAccessKey = os.Getenv("IIJ_API_ACCESS_KEY")
+	envTestAPISecretKeyEnv = os.Getenv("IIJ_API_SECRET_KEY")
+	envTestDoServiceCodeEnv = os.Getenv("IIJ_DO_SERVICE_CODE")
 
-	testDomain = os.Getenv("IIJ_API_TESTDOMAIN")
+	envTestDomain = os.Getenv("IIJ_API_TESTDOMAIN")
 
-	if len(apiAccessKeyEnv) > 0 && len(apiSecretKeyEnv) > 0 && len(doServiceCodeEnv) > 0 && len(testDomain) > 0 {
+	if len(envTestAPIAccessKey) > 0 && len(envTestAPISecretKeyEnv) > 0 && len(envTestDoServiceCodeEnv) > 0 && len(envTestDomain) > 0 {
 		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("IIJ_API_ACCESS_KEY", apiAccessKeyEnv)
-	os.Setenv("IIJ_API_SECRET_KEY", apiSecretKeyEnv)
-	os.Setenv("IIJ_DO_SERVICE_CODE", doServiceCodeEnv)
-	os.Setenv("IIJ_API_TESTDOMAIN", testDomain)
+	os.Setenv("IIJ_API_ACCESS_KEY", envTestAPIAccessKey)
+	os.Setenv("IIJ_API_SECRET_KEY", envTestAPISecretKeyEnv)
+	os.Setenv("IIJ_DO_SERVICE_CODE", envTestDoServiceCodeEnv)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"IIJ_API_ACCESS_KEY":  "A",
+				"IIJ_API_SECRET_KEY":  "B",
+				"IIJ_DO_SERVICE_CODE": "C",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"IIJ_API_ACCESS_KEY":  "",
+				"IIJ_API_SECRET_KEY":  "",
+				"IIJ_DO_SERVICE_CODE": "",
+			},
+			expected: "iij: some credentials information are missing: IIJ_API_ACCESS_KEY,IIJ_API_SECRET_KEY,IIJ_DO_SERVICE_CODE",
+		},
+		{
+			desc: "missing api access key",
+			envVars: map[string]string{
+				"IIJ_API_ACCESS_KEY":  "",
+				"IIJ_API_SECRET_KEY":  "B",
+				"IIJ_DO_SERVICE_CODE": "C",
+			},
+			expected: "iij: some credentials information are missing: IIJ_API_ACCESS_KEY",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"IIJ_API_ACCESS_KEY":  "A",
+				"IIJ_API_SECRET_KEY":  "",
+				"IIJ_DO_SERVICE_CODE": "C",
+			},
+			expected: "iij: some credentials information are missing: IIJ_API_SECRET_KEY",
+		},
+		{
+			desc: "missing do service code",
+			envVars: map[string]string{
+				"IIJ_API_ACCESS_KEY":  "A",
+				"IIJ_API_SECRET_KEY":  "B",
+				"IIJ_DO_SERVICE_CODE": "",
+			},
+			expected: "iij: some credentials information are missing: IIJ_DO_SERVICE_CODE",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.api)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc          string
+		accessKey     string
+		secretKey     string
+		doServiceCode string
+		expected      string
+	}{
+		{
+			desc:          "success",
+			accessKey:     "A",
+			secretKey:     "B",
+			doServiceCode: "C",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "iij: credentials missing",
+		},
+		{
+			desc:          "missing access key",
+			accessKey:     "",
+			secretKey:     "B",
+			doServiceCode: "C",
+			expected:      "iij: credentials missing",
+		},
+		{
+			desc:          "missing secret key",
+			accessKey:     "A",
+			secretKey:     "",
+			doServiceCode: "C",
+			expected:      "iij: credentials missing",
+		},
+		{
+			desc:          "missing do service code",
+			accessKey:     "A",
+			secretKey:     "B",
+			doServiceCode: "",
+			expected:      "iij: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("IIJ_API_ACCESS_KEY")
+			os.Unsetenv("IIJ_API_SECRET_KEY")
+			os.Unsetenv("IIJ_DO_SERVICE_CODE")
+
+			config := NewDefaultConfig()
+			config.AccessKey = test.accessKey
+			config.SecretKey = test.secretKey
+			config.DoServiceCode = test.doServiceCode
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.api)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func TestSplitDomain(t *testing.T) {
@@ -88,45 +231,28 @@ func TestSplitDomain(t *testing.T) {
 
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("IIJ_API_ACCESS_KEY", "")
-	os.Setenv("IIJ_API_SECRET_KEY", "")
-	os.Setenv("IIJ_DO_SERVICE_CODE", "")
-
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "iij: some credentials information are missing: IIJ_API_ACCESS_KEY,IIJ_API_SECRET_KEY,IIJ_DO_SERVICE_CODE")
-}
-
-func TestNewDNSProvider(t *testing.T) {
-	if !liveTest {
-		t.Skip("skipping live test")
-	}
-
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
-}
-
-func TestDNSProvider_Present(t *testing.T) {
+func TestLivePresent(t *testing.T) {
 	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.Present(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
 
-func TestDNSProvider_CleanUp(t *testing.T) {
+func TestLiveCleanUp(t *testing.T) {
 	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	err = provider.CleanUp(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
 }
diff --git a/providers/dns/lightsail/lightsail_integration_test.go b/providers/dns/lightsail/lightsail_integration_test.go
index b81e1a55..729cc900 100644
--- a/providers/dns/lightsail/lightsail_integration_test.go
+++ b/providers/dns/lightsail/lightsail_integration_test.go
@@ -11,7 +11,7 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func TestLightsailTTL(t *testing.T) {
+func TestLiveTTL(t *testing.T) {
 	m, err := testGetAndPreCheck()
 	if err != nil {
 		t.Skip(err.Error())
@@ -20,14 +20,14 @@ func TestLightsailTTL(t *testing.T) {
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	lightsailDomain := m["lightsailDomain"]
+	domain := m["lightsailDomain"]
 
-	err = provider.Present(lightsailDomain, "foo", "bar")
+	err = provider.Present(domain, "foo", "bar")
 	require.NoError(t, err)
 
-	// we need a separate Lightshail client here as the one in the DNS provider is
+	// we need a separate Lightsail client here as the one in the DNS provider is
 	// unexported.
-	fqdn := "_acme-challenge." + lightsailDomain
+	fqdn := "_acme-challenge." + domain
 	sess, err := session.NewSession()
 	require.NoError(t, err)
 
@@ -35,14 +35,14 @@ func TestLightsailTTL(t *testing.T) {
 	require.NoError(t, err)
 
 	defer func() {
-		errC := provider.CleanUp(lightsailDomain, "foo", "bar")
+		errC := provider.CleanUp(domain, "foo", "bar")
 		if errC != nil {
 			t.Log(errC)
 		}
 	}()
 
 	params := &lightsail.GetDomainInput{
-		DomainName: aws.String(lightsailDomain),
+		DomainName: aws.String(domain),
 	}
 
 	resp, err := svc.GetDomain(params)
@@ -55,7 +55,7 @@ func TestLightsailTTL(t *testing.T) {
 		}
 	}
 
-	t.Fatalf("Could not find a TXT record for _acme-challenge.%s", lightsailDomain)
+	t.Fatalf("Could not find a TXT record for _acme-challenge.%s", domain)
 }
 
 func testGetAndPreCheck() (map[string]string, error) {
diff --git a/providers/dns/lightsail/lightsail_test.go b/providers/dns/lightsail/lightsail_test.go
index cf0ca84e..da53257c 100644
--- a/providers/dns/lightsail/lightsail_test.go
+++ b/providers/dns/lightsail/lightsail_test.go
@@ -13,24 +13,24 @@ import (
 )
 
 var (
-	lightsailSecret string
-	lightsailKey    string
-	lightsailZone   string
+	envTestSecret string
+	envTestKey    string
+	envTestZone   string
 )
 
 func init() {
-	lightsailKey = os.Getenv("AWS_ACCESS_KEY_ID")
-	lightsailSecret = os.Getenv("AWS_SECRET_ACCESS_KEY")
+	envTestKey = os.Getenv("AWS_ACCESS_KEY_ID")
+	envTestSecret = os.Getenv("AWS_SECRET_ACCESS_KEY")
 }
 
 func restoreEnv() {
-	os.Setenv("AWS_ACCESS_KEY_ID", lightsailKey)
-	os.Setenv("AWS_SECRET_ACCESS_KEY", lightsailSecret)
+	os.Setenv("AWS_ACCESS_KEY_ID", envTestKey)
+	os.Setenv("AWS_SECRET_ACCESS_KEY", envTestSecret)
 	os.Setenv("AWS_REGION", "us-east-1")
-	os.Setenv("AWS_HOSTED_ZONE_ID", lightsailZone)
+	os.Setenv("AWS_HOSTED_ZONE_ID", envTestZone)
 }
 
-func makeLightsailProvider(ts *httptest.Server) (*DNSProvider, error) {
+func makeProvider(ts *httptest.Server) (*DNSProvider, error) {
 	config := &aws.Config{
 		Credentials: credentials.NewStaticCredentials("abc", "123", " "),
 		Endpoint:    aws.String(ts.URL),
@@ -66,7 +66,7 @@ func TestCredentialsFromEnv(t *testing.T) {
 	require.NoError(t, err, "Expected credentials to be set from environment")
 }
 
-func TestLightsailPresent(t *testing.T) {
+func TestDNSProvider_Present(t *testing.T) {
 	mockResponses := map[string]MockResponse{
 		"/": {StatusCode: 200, Body: ""},
 	}
@@ -74,7 +74,7 @@ func TestLightsailPresent(t *testing.T) {
 	ts := newMockServer(t, mockResponses)
 	defer ts.Close()
 
-	provider, err := makeLightsailProvider(ts)
+	provider, err := makeProvider(ts)
 	require.NoError(t, err)
 
 	domain := "example.com"
diff --git a/providers/dns/linode/linode_test.go b/providers/dns/linode/linode_test.go
index 702da864..1b9d9365 100644
--- a/providers/dns/linode/linode_test.go
+++ b/providers/dns/linode/linode_test.go
@@ -16,7 +16,7 @@ import (
 )
 
 type (
-	LinodeResponse struct {
+	apiResponse struct {
 		Action string                 `json:"ACTION"`
 		Data   interface{}            `json:"DATA"`
 		Errors []linode.ResponseError `json:"ERRORARRAY"`
@@ -29,38 +29,41 @@ type (
 )
 
 var (
-	apiKey     string
-	isTestLive bool
+	apiKey   string
+	liveTest bool
 )
 
 func init() {
 	apiKey = os.Getenv("LINODE_API_KEY")
-	isTestLive = len(apiKey) != 0
+
+	liveTest = len(apiKey) != 0
 }
 
 func restoreEnv() {
 	os.Setenv("LINODE_API_KEY", apiKey)
 }
 
-func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
+func newMockServer(responses MockResponseMap) *httptest.Server {
 	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		// Ensure that we support the requested action.
 		action := r.URL.Query().Get("api_action")
 		resp, ok := responses[action]
 		if !ok {
-			require.FailNowf(t, "Unsupported mock action: %q", action)
+			http.Error(w, fmt.Sprintf("Unsupported mock action: %q", action), http.StatusInternalServerError)
+			return
 		}
 
 		// Build the response that the server will return.
-		linodeResponse := LinodeResponse{
+		response := apiResponse{
 			Action: action,
 			Data:   resp.Response,
 			Errors: resp.Errors,
 		}
-		rawResponse, err := json.Marshal(linodeResponse)
+
+		rawResponse, err := json.Marshal(response)
 		if err != nil {
-			msg := fmt.Sprintf("Failed to JSON encode response: %v", err)
-			require.FailNow(t, msg)
+			http.Error(w, fmt.Sprintf("Failed to JSON encode response: %v", err), http.StatusInternalServerError)
+			return
 		}
 
 		// Send the response.
@@ -77,35 +80,88 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
 	return srv
 }
 
-func TestNewDNSProviderWithEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_API_KEY", "testing")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"LINODE_API_KEY": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"LINODE_API_KEY": "",
+			},
+			expected: "linode: some credentials information are missing: LINODE_API_KEY",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
-}
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
 
-func TestNewDNSProviderWithoutEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_API_KEY", "")
+			p, err := NewDNSProvider()
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "linode: some credentials information are missing: LINODE_API_KEY")
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderWithKey(t *testing.T) {
-	config := NewDefaultConfig()
-	config.APIKey = "testing"
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "linode: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("LINODE_API_KEY")
 
-	_, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-}
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
 
-func TestNewDNSProviderWithoutKey(t *testing.T) {
-	config := NewDefaultConfig()
+			p, err := NewDNSProviderConfig(config)
 
-	_, err := NewDNSProviderConfig(config)
-	assert.EqualError(t, err, "linode: credentials missing")
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func TestDNSProvider_Present(t *testing.T) {
@@ -180,11 +236,10 @@ func TestDNSProvider_Present(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.desc, func(t *testing.T) {
+			server := newMockServer(test.mockResponses)
+			defer server.Close()
 
-			mockSrv := newMockServer(t, test.mockResponses)
-			defer mockSrv.Close()
-
-			p.client.ToLinode().SetEndpoint(mockSrv.URL)
+			p.client.ToLinode().SetEndpoint(server.URL)
 
 			err = p.Present(domain, "", keyAuth)
 			if len(test.expectedError) == 0 {
@@ -196,13 +251,6 @@ func TestDNSProvider_Present(t *testing.T) {
 	}
 }
 
-func TestDNSProvider_PresentLive(t *testing.T) {
-	if !isTestLive {
-		t.Skip("Skipping live test")
-	}
-	// TODO implement this test
-}
-
 func TestDNSProvider_CleanUp(t *testing.T) {
 	defer restoreEnv()
 	os.Setenv("LINODE_API_KEY", "testing")
@@ -299,10 +347,10 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.desc, func(t *testing.T) {
-			mockSrv := newMockServer(t, test.mockResponses)
-			defer mockSrv.Close()
+			server := newMockServer(test.mockResponses)
+			defer server.Close()
 
-			p.client.ToLinode().SetEndpoint(mockSrv.URL)
+			p.client.ToLinode().SetEndpoint(server.URL)
 
 			err = p.CleanUp(domain, "", keyAuth)
 			if len(test.expectedError) == 0 {
@@ -313,3 +361,17 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 		})
 	}
 }
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
+		t.Skip("Skipping live test")
+	}
+	// TODO implement this test
+}
+
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
+		t.Skip("Skipping live test")
+	}
+	// TODO implement this test
+}
diff --git a/providers/dns/linodev4/linodev4_test.go b/providers/dns/linodev4/linodev4_test.go
index 4f0bd16e..ab88de64 100644
--- a/providers/dns/linodev4/linodev4_test.go
+++ b/providers/dns/linodev4/linodev4_test.go
@@ -19,32 +19,34 @@ type (
 )
 
 var (
-	apiToken   string
-	isTestLive bool
+	liveTest        bool
+	envTestAPIToken string
 )
 
 func init() {
-	apiToken = os.Getenv("LINODE_TOKEN")
-	isTestLive = len(apiToken) != 0
+	envTestAPIToken = os.Getenv("LINODE_TOKEN")
+
+	liveTest = len(envTestAPIToken) != 0
 }
 
 func restoreEnv() {
-	os.Setenv("LINODE_TOKEN", apiToken)
+	os.Setenv("LINODE_TOKEN", envTestAPIToken)
 }
 
-func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
+func newMockServer(responses MockResponseMap) *httptest.Server {
 	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		// Ensure that we support the requested action.
 		action := r.Method + ":" + r.URL.Path
 		resp, ok := responses[action]
 		if !ok {
-			require.FailNowf(t, "Unsupported mock", "action: %s", action)
+			http.Error(w, fmt.Sprintf("Unsupported mock action: %q", action), http.StatusInternalServerError)
+			return
 		}
 
 		rawResponse, err := json.Marshal(resp)
 		if err != nil {
-			msg := fmt.Sprintf("Failed to JSON encode response: %v", err)
-			require.FailNow(t, msg)
+			http.Error(w, fmt.Sprintf("Failed to JSON encode response: %v", err), http.StatusInternalServerError)
+			return
 		}
 
 		// Send the response.
@@ -69,36 +71,88 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
 	return srv
 }
 
-func TestNewDNSProviderWithEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_TOKEN", "testing")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"LINODE_TOKEN": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"LINODE_TOKEN": "",
+			},
+			expected: "linodev4: some credentials information are missing: LINODE_TOKEN",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.NoError(t, err)
-}
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
 
-func TestNewDNSProviderWithoutEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_TOKEN", "")
+			p, err := NewDNSProvider()
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "linodev4: some credentials information are missing: LINODE_TOKEN")
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderWithKey(t *testing.T) {
-	config := NewDefaultConfig()
-	config.Token = "testing"
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "linodev4: Linode Access Token missing",
+		},
+	}
 
-	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
-}
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("LINODE_TOKEN")
+
+			config := NewDefaultConfig()
+			config.Token = test.apiKey
 
-func TestNewDNSProviderWithoutKey(t *testing.T) {
-	config := NewDefaultConfig()
-	config.Token = ""
+			p, err := NewDNSProviderConfig(config)
 
-	_, err := NewDNSProviderConfig(config)
-	assert.EqualError(t, err, "linodev4: Linode Access Token missing")
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func TestDNSProvider_Present(t *testing.T) {
@@ -175,11 +229,11 @@ func TestDNSProvider_Present(t *testing.T) {
 	for _, test := range testCases {
 		t.Run(test.desc, func(t *testing.T) {
 
-			mockSrv := newMockServer(t, test.mockResponses)
-			defer mockSrv.Close()
+			server := newMockServer(test.mockResponses)
+			defer server.Close()
 
 			assert.NotNil(t, p.client)
-			p.client.SetBaseURL(mockSrv.URL)
+			p.client.SetBaseURL(server.URL)
 
 			err = p.Present(domain, "", keyAuth)
 			if len(test.expectedError) == 0 {
@@ -191,13 +245,6 @@ func TestDNSProvider_Present(t *testing.T) {
 	}
 }
 
-func TestDNSProvider_PresentLive(t *testing.T) {
-	if !isTestLive {
-		t.Skip("Skipping live test")
-	}
-	// TODO implement this test
-}
-
 func TestDNSProvider_CleanUp(t *testing.T) {
 	defer restoreEnv()
 	os.Setenv("LINODE_TOKEN", "testing")
@@ -298,10 +345,10 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.desc, func(t *testing.T) {
-			mockSrv := newMockServer(t, test.mockResponses)
-			defer mockSrv.Close()
+			server := newMockServer(test.mockResponses)
+			defer server.Close()
 
-			p.client.SetBaseURL(mockSrv.URL)
+			p.client.SetBaseURL(server.URL)
 
 			err = p.CleanUp(domain, "", keyAuth)
 			if len(test.expectedError) == 0 {
@@ -312,3 +359,17 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 		})
 	}
 }
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
+		t.Skip("Skipping live test")
+	}
+	// TODO implement this test
+}
+
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
+		t.Skip("Skipping live test")
+	}
+	// TODO implement this test
+}
diff --git a/providers/dns/namecheap/namecheap_test.go b/providers/dns/namecheap/namecheap_test.go
index f5f00134..f3fd0705 100644
--- a/providers/dns/namecheap/namecheap_test.go
+++ b/providers/dns/namecheap/namecheap_test.go
@@ -13,9 +13,9 @@ import (
 )
 
 var (
-	fakeUser     = "foo"
-	fakeKey      = "bar"
-	fakeClientIP = "10.0.0.1"
+	envTestUser     = "foo"
+	envTestKey      = "bar"
+	envTestClientIP = "10.0.0.1"
 
 	tlds = map[string]string{
 		"com.au": "com.au",
@@ -28,24 +28,13 @@ var (
 	}
 )
 
-func TestGetHosts(t *testing.T) {
+func TestDNSProvider_getHosts(t *testing.T) {
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			mock := httptest.NewServer(http.HandlerFunc(
-				func(w http.ResponseWriter, r *http.Request) {
-					mockServer(&test, t, w, r)
-				}))
+			mock := httptest.NewServer(mockServer(&test, t))
 			defer mock.Close()
 
-			config := NewDefaultConfig()
-			config.BaseURL = mock.URL
-			config.APIUser = fakeUser
-			config.APIKey = fakeKey
-			config.ClientIP = fakeClientIP
-			config.HTTPClient = &http.Client{Timeout: 60 * time.Second}
-
-			provider, err := NewDNSProviderConfig(config)
-			require.NoError(t, err)
+			provider := mockDNSProvider(mock.URL)
 
 			ch, err := newChallenge(test.domain, "", tlds)
 			require.NoError(t, err)
@@ -80,13 +69,10 @@ func TestGetHosts(t *testing.T) {
 	}
 }
 
-func TestSetHosts(t *testing.T) {
+func TestDNSProvider_setHosts(t *testing.T) {
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			mock := httptest.NewServer(http.HandlerFunc(
-				func(w http.ResponseWriter, r *http.Request) {
-					mockServer(&test, t, w, r)
-				}))
+			mock := httptest.NewServer(mockServer(&test, t))
 			defer mock.Close()
 
 			prov := mockDNSProvider(mock.URL)
@@ -110,13 +96,10 @@ func TestSetHosts(t *testing.T) {
 	}
 }
 
-func TestPresent(t *testing.T) {
+func TestDNSProvider_Present(t *testing.T) {
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			mock := httptest.NewServer(http.HandlerFunc(
-				func(w http.ResponseWriter, r *http.Request) {
-					mockServer(&test, t, w, r)
-				}))
+			mock := httptest.NewServer(mockServer(&test, t))
 			defer mock.Close()
 
 			prov := mockDNSProvider(mock.URL)
@@ -130,13 +113,10 @@ func TestPresent(t *testing.T) {
 	}
 }
 
-func TestCleanUp(t *testing.T) {
+func TestDNSProvider_CleanUp(t *testing.T) {
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			mock := httptest.NewServer(http.HandlerFunc(
-				func(w http.ResponseWriter, r *http.Request) {
-					mockServer(&test, t, w, r)
-				}))
+			mock := httptest.NewServer(mockServer(&test, t))
 			defer mock.Close()
 
 			prov := mockDNSProvider(mock.URL)
@@ -210,60 +190,61 @@ func assertEq(t *testing.T, variable, got, want string) {
 func assertHdr(tc *testCase, t *testing.T, values *url.Values) {
 	ch, _ := newChallenge(tc.domain, "", tlds)
 
-	assertEq(t, "ApiUser", values.Get("ApiUser"), fakeUser)
-	assertEq(t, "ApiKey", values.Get("ApiKey"), fakeKey)
-	assertEq(t, "UserName", values.Get("UserName"), fakeUser)
-	assertEq(t, "ClientIp", values.Get("ClientIp"), fakeClientIP)
+	assertEq(t, "ApiUser", values.Get("ApiUser"), envTestUser)
+	assertEq(t, "ApiKey", values.Get("ApiKey"), envTestKey)
+	assertEq(t, "UserName", values.Get("UserName"), envTestUser)
+	assertEq(t, "ClientIp", values.Get("ClientIp"), envTestClientIP)
 	assertEq(t, "SLD", values.Get("SLD"), ch.sld)
 	assertEq(t, "TLD", values.Get("TLD"), ch.tld)
 }
 
-func mockServer(tc *testCase, t *testing.T, w http.ResponseWriter, r *http.Request) {
-	switch r.Method {
-
-	case http.MethodGet:
-		values := r.URL.Query()
-		cmd := values.Get("Command")
-		switch cmd {
-		case "namecheap.domains.dns.getHosts":
-			assertHdr(tc, t, &values)
-			w.WriteHeader(http.StatusOK)
-			fmt.Fprintf(w, tc.getHostsResponse)
-		case "namecheap.domains.getTldList":
-			w.WriteHeader(http.StatusOK)
-			fmt.Fprintf(w, responseGetTlds)
-		default:
-			t.Errorf("Unexpected GET command: %s", cmd)
-		}
+func mockServer(tc *testCase, t *testing.T) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		switch r.Method {
+		case http.MethodGet:
+			values := r.URL.Query()
+			cmd := values.Get("Command")
+			switch cmd {
+			case "namecheap.domains.dns.getHosts":
+				assertHdr(tc, t, &values)
+				w.WriteHeader(http.StatusOK)
+				fmt.Fprintf(w, tc.getHostsResponse)
+			case "namecheap.domains.getTldList":
+				w.WriteHeader(http.StatusOK)
+				fmt.Fprintf(w, responseGetTlds)
+			default:
+				t.Errorf("Unexpected GET command: %s", cmd)
+			}
+
+		case http.MethodPost:
+			err := r.ParseForm()
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
+			values := r.Form
+			cmd := values.Get("Command")
+			switch cmd {
+			case "namecheap.domains.dns.setHosts":
+				assertHdr(tc, t, &values)
+				w.WriteHeader(http.StatusOK)
+				fmt.Fprint(w, tc.setHostsResponse)
+			default:
+				t.Errorf("Unexpected POST command: %s", cmd)
+			}
 
-	case http.MethodPost:
-		err := r.ParseForm()
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-		values := r.Form
-		cmd := values.Get("Command")
-		switch cmd {
-		case "namecheap.domains.dns.setHosts":
-			assertHdr(tc, t, &values)
-			w.WriteHeader(http.StatusOK)
-			fmt.Fprint(w, tc.setHostsResponse)
 		default:
-			t.Errorf("Unexpected POST command: %s", cmd)
+			t.Errorf("Unexpected http method: %s", r.Method)
 		}
-
-	default:
-		t.Errorf("Unexpected http method: %s", r.Method)
-	}
+	})
 }
 
 func mockDNSProvider(url string) *DNSProvider {
 	config := NewDefaultConfig()
 	config.BaseURL = url
-	config.APIUser = fakeUser
-	config.APIKey = fakeKey
-	config.ClientIP = fakeClientIP
+	config.APIUser = envTestUser
+	config.APIKey = envTestKey
+	config.ClientIP = envTestClientIP
 	config.HTTPClient = &http.Client{Timeout: 60 * time.Second}
 
 	provider, err := NewDNSProviderConfig(config)
diff --git a/providers/dns/namedotcom/namedotcom_test.go b/providers/dns/namedotcom/namedotcom_test.go
index 85a0d117..144aa2ed 100644
--- a/providers/dns/namedotcom/namedotcom_test.go
+++ b/providers/dns/namedotcom/namedotcom_test.go
@@ -9,60 +9,169 @@ import (
 )
 
 var (
-	namedotcomLiveTest bool
-	namedotcomUsername string
-	namedotcomAPIToken string
-	namedotcomDomain   string
-	namedotcomServer   string
+	liveTest        bool
+	envTestUsername string
+	envTestAPIToken string
+	envTestDomain   string
 )
 
 func init() {
-	namedotcomUsername = os.Getenv("NAMEDOTCOM_USERNAME")
-	namedotcomAPIToken = os.Getenv("NAMEDOTCOM_API_TOKEN")
-	namedotcomDomain = os.Getenv("NAMEDOTCOM_DOMAIN")
-	namedotcomServer = os.Getenv("NAMEDOTCOM_SERVER")
+	envTestUsername = os.Getenv("NAMECOM_USERNAME")
+	envTestAPIToken = os.Getenv("NAMECOM_API_TOKEN")
+	envTestDomain = os.Getenv("NAMEDOTCOM_DOMAIN")
 
-	if len(namedotcomAPIToken) > 0 && len(namedotcomUsername) > 0 && len(namedotcomDomain) > 0 {
-		namedotcomLiveTest = true
+	if len(envTestAPIToken) > 0 && len(envTestUsername) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
-func TestLiveNamedotcomPresent(t *testing.T) {
-	if !namedotcomLiveTest {
-		t.Skip("skipping live test")
+func restoreEnv() {
+	os.Setenv("NAMECOM_USERNAME", envTestUsername)
+	os.Setenv("NAMECOM_API_TOKEN", envTestAPIToken)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"NAMECOM_USERNAME":  "A",
+				"NAMECOM_API_TOKEN": "B",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"NAMECOM_USERNAME":  "",
+				"NAMECOM_API_TOKEN": "",
+			},
+			expected: "namedotcom: some credentials information are missing: NAMECOM_USERNAME,NAMECOM_API_TOKEN",
+		},
+		{
+			desc: "missing username",
+			envVars: map[string]string{
+				"NAMECOM_USERNAME":  "",
+				"NAMECOM_API_TOKEN": "B",
+			},
+			expected: "namedotcom: some credentials information are missing: NAMECOM_USERNAME",
+		},
+		{
+			desc: "missing api token",
+			envVars: map[string]string{
+				"NAMECOM_USERNAME":  "A",
+				"NAMECOM_API_TOKEN": "",
+			},
+			expected: "namedotcom: some credentials information are missing: NAMECOM_API_TOKEN",
+		},
 	}
 
-	config := NewDefaultConfig()
-	config.Username = namedotcomUsername
-	config.APIToken = namedotcomAPIToken
-	config.Server = namedotcomServer
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
 
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
+			p, err := NewDNSProvider()
 
-	err = provider.Present(namedotcomDomain, "", "123d==")
-	require.NoError(t, err)
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-//
-// Cleanup
-//
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiToken string
+		username string
+		expected string
+	}{
+		{
+			desc:     "success",
+			apiToken: "A",
+			username: "B",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "namedotcom: username is required",
+		},
+		{
+			desc:     "missing API token",
+			apiToken: "",
+			username: "B",
+			expected: "namedotcom: API token is required",
+		},
+		{
+			desc:     "missing username",
+			apiToken: "A",
+			username: "",
+			expected: "namedotcom: username is required",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("NAMECOM_USERNAME")
+			os.Unsetenv("NAMECOM_API_TOKEN")
+
+			config := NewDefaultConfig()
+			config.Username = test.username
+			config.APIToken = test.apiToken
+
+			p, err := NewDNSProviderConfig(config)
 
-func TestLiveNamedotcomCleanUp(t *testing.T) {
-	if !namedotcomLiveTest {
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
+}
 
-	config := NewDefaultConfig()
-	config.Username = namedotcomUsername
-	config.APIToken = namedotcomAPIToken
-	config.Server = namedotcomServer
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
+	}
 
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(namedotcomDomain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/netcup/client_test.go b/providers/dns/netcup/client_test.go
index cba491b0..8b6cdc4f 100644
--- a/providers/dns/netcup/client_test.go
+++ b/providers/dns/netcup/client_test.go
@@ -6,16 +6,17 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/xenolf/lego/acme"
 )
 
-func TestClientAuth(t *testing.T) {
-	if !testLive {
+func TestLiveClientAuth(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
 	// Setup
-	client := NewClient(testCustomerNumber, testAPIKey, testAPIPassword)
+	client := NewClient(envTestCustomerNumber, envTestAPIKey, envTestAPIPassword)
 
 	for i := 1; i < 4; i++ {
 		i := i
@@ -23,57 +24,57 @@ func TestClientAuth(t *testing.T) {
 			t.Parallel()
 
 			sessionID, err := client.Login()
-			assert.NoError(t, err)
+			require.NoError(t, err)
 
 			err = client.Logout(sessionID)
-			assert.NoError(t, err)
+			require.NoError(t, err)
 		})
 	}
 
 }
 
-func TestClientGetDnsRecords(t *testing.T) {
-	if !testLive {
+func TestLiveClientGetDnsRecords(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	client := NewClient(testCustomerNumber, testAPIKey, testAPIPassword)
+	client := NewClient(envTestCustomerNumber, envTestAPIKey, envTestAPIPassword)
 
 	// Setup
 	sessionID, err := client.Login()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	fqdn, _, _ := acme.DNS01Record(testDomain, "123d==")
+	fqdn, _, _ := acme.DNS01Record(envTestDomain, "123d==")
 
 	zone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
-	assert.NoError(t, err, "error finding DNSZone")
+	require.NoError(t, err, "error finding DNSZone")
 
 	zone = acme.UnFqdn(zone)
 
 	// TestMethod
 	_, err = client.GetDNSRecords(zone, sessionID)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	// Tear down
 	err = client.Logout(sessionID)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
-func TestClientUpdateDnsRecord(t *testing.T) {
-	if !testLive {
+func TestLiveClientUpdateDnsRecord(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
 	// Setup
-	client := NewClient(testCustomerNumber, testAPIKey, testAPIPassword)
+	client := NewClient(envTestCustomerNumber, envTestAPIKey, envTestAPIPassword)
 
 	sessionID, err := client.Login()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	fqdn, _, _ := acme.DNS01Record(testDomain, "123d==")
+	fqdn, _, _ := acme.DNS01Record(envTestDomain, "123d==")
 
 	zone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
-	assert.NoError(t, err, fmt.Errorf("error finding DNSZone, %v", err))
+	require.NoError(t, err, fmt.Errorf("error finding DNSZone, %v", err))
 
 	hostname := strings.Replace(fqdn, "."+zone, "", 1)
 
@@ -83,13 +84,13 @@ func TestClientUpdateDnsRecord(t *testing.T) {
 	zone = acme.UnFqdn(zone)
 
 	err = client.UpdateDNSRecord(sessionID, zone, record)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	records, err := client.GetDNSRecords(zone, sessionID)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	recordIdx, err := GetDNSRecordIdx(records, record)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, record.Hostname, records[recordIdx].Hostname)
 	assert.Equal(t, record.RecordType, records[recordIdx].RecordType)
@@ -99,11 +100,11 @@ func TestClientUpdateDnsRecord(t *testing.T) {
 	records[recordIdx].DeleteRecord = true
 
 	// Tear down
-	err = client.UpdateDNSRecord(sessionID, testDomain, records[recordIdx])
-	assert.NoError(t, err, "Did not remove record! Please do so yourself.")
+	err = client.UpdateDNSRecord(sessionID, envTestDomain, records[recordIdx])
+	require.NoError(t, err, "Did not remove record! Please do so yourself.")
 
 	err = client.Logout(sessionID)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestClientGetDnsRecordIdx(t *testing.T) {
diff --git a/providers/dns/netcup/netcup_test.go b/providers/dns/netcup/netcup_test.go
index 1c8c1b8a..4460e0ca 100644
--- a/providers/dns/netcup/netcup_test.go
+++ b/providers/dns/netcup/netcup_test.go
@@ -5,41 +5,192 @@ import (
 	"os"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/xenolf/lego/acme"
 )
 
 var (
-	testLive           bool
-	testCustomerNumber string
-	testAPIKey         string
-	testAPIPassword    string
-	testDomain         string
+	liveTest              bool
+	envTestCustomerNumber string
+	envTestAPIKey         string
+	envTestAPIPassword    string
+	envTestDomain         string
 )
 
 func init() {
-	testCustomerNumber = os.Getenv("NETCUP_CUSTOMER_NUMBER")
-	testAPIKey = os.Getenv("NETCUP_API_KEY")
-	testAPIPassword = os.Getenv("NETCUP_API_PASSWORD")
-	testDomain = os.Getenv("NETCUP_DOMAIN")
+	envTestCustomerNumber = os.Getenv("NETCUP_CUSTOMER_NUMBER")
+	envTestAPIKey = os.Getenv("NETCUP_API_KEY")
+	envTestAPIPassword = os.Getenv("NETCUP_API_PASSWORD")
+	envTestDomain = os.Getenv("NETCUP_DOMAIN")
 
-	if len(testCustomerNumber) > 0 && len(testAPIKey) > 0 && len(testAPIPassword) > 0 && len(testDomain) > 0 {
-		testLive = true
+	if len(envTestCustomerNumber) > 0 && len(envTestAPIKey) > 0 && len(envTestAPIPassword) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
-func TestDNSProviderPresentAndCleanup(t *testing.T) {
-	if !testLive {
+func restoreEnv() {
+	os.Setenv("NETCUP_CUSTOMER_NUMBER", envTestCustomerNumber)
+	os.Setenv("NETCUP_API_KEY", envTestAPIKey)
+	os.Setenv("NETCUP_API_PASSWORD", envTestAPIPassword)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"NETCUP_CUSTOMER_NUMBER": "A",
+				"NETCUP_API_KEY":         "B",
+				"NETCUP_API_PASSWORD":    "C",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"NETCUP_CUSTOMER_NUMBER": "",
+				"NETCUP_API_KEY":         "",
+				"NETCUP_API_PASSWORD":    "",
+			},
+			expected: "netcup: some credentials information are missing: NETCUP_CUSTOMER_NUMBER,NETCUP_API_KEY,NETCUP_API_PASSWORD",
+		},
+		{
+			desc: "missing customer number",
+			envVars: map[string]string{
+				"NETCUP_CUSTOMER_NUMBER": "",
+				"NETCUP_API_KEY":         "B",
+				"NETCUP_API_PASSWORD":    "C",
+			},
+			expected: "netcup: some credentials information are missing: NETCUP_CUSTOMER_NUMBER",
+		},
+		{
+			desc: "missing API key",
+			envVars: map[string]string{
+				"NETCUP_CUSTOMER_NUMBER": "A",
+				"NETCUP_API_KEY":         "",
+				"NETCUP_API_PASSWORD":    "C",
+			},
+			expected: "netcup: some credentials information are missing: NETCUP_API_KEY",
+		},
+		{
+			desc: "missing api password",
+			envVars: map[string]string{
+				"NETCUP_CUSTOMER_NUMBER": "A",
+				"NETCUP_API_KEY":         "B",
+				"NETCUP_API_PASSWORD":    "",
+			},
+			expected: "netcup: some credentials information are missing: NETCUP_API_PASSWORD",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		customer string
+		key      string
+		password string
+		expected string
+	}{
+		{
+			desc:     "success",
+			customer: "A",
+			key:      "B",
+			password: "C",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "netcup: netcup credentials missing",
+		},
+		{
+			desc:     "missing customer",
+			customer: "",
+			key:      "B",
+			password: "C",
+			expected: "netcup: netcup credentials missing",
+		},
+		{
+			desc:     "missing key",
+			customer: "A",
+			key:      "",
+			password: "C",
+			expected: "netcup: netcup credentials missing",
+		},
+		{
+			desc:     "missing password",
+			customer: "A",
+			key:      "B",
+			password: "",
+			expected: "netcup: netcup credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("NETCUP_CUSTOMER_NUMBER")
+			os.Unsetenv("NETCUP_API_KEY")
+			os.Unsetenv("NETCUP_API_PASSWORD")
+
+			config := NewDefaultConfig()
+			config.Customer = test.customer
+			config.Key = test.key
+			config.Password = test.password
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestLivePresentAndCleanup(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	p, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	fqdn, _, _ := acme.DNS01Record(testDomain, "123d==")
+	fqdn, _, _ := acme.DNS01Record(envTestDomain, "123d==")
 
 	zone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
-	assert.NoError(t, err, "error finding DNSZone")
+	require.NoError(t, err, "error finding DNSZone")
 
 	zone = acme.UnFqdn(zone)
 
@@ -53,10 +204,10 @@ func TestDNSProviderPresentAndCleanup(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(fmt.Sprintf("domain(%s)", tc), func(t *testing.T) {
 			err = p.Present(tc, "987d", "123d==")
-			assert.NoError(t, err)
+			require.NoError(t, err)
 
 			err = p.CleanUp(tc, "987d", "123d==")
-			assert.NoError(t, err, "Did not clean up! Please remove record yourself.")
+			require.NoError(t, err, "Did not clean up! Please remove record yourself.")
 		})
 	}
 }
diff --git a/providers/dns/nifcloud/client_test.go b/providers/dns/nifcloud/client_test.go
index e56ccd37..f940c4ee 100644
--- a/providers/dns/nifcloud/client_test.go
+++ b/providers/dns/nifcloud/client_test.go
@@ -31,7 +31,9 @@ func TestChangeResourceRecordSets(t *testing.T) {
 	server := runTestServer(responseBody, http.StatusOK)
 	defer server.Close()
 
-	client := NewClient("", "")
+	client, err := NewClient("A", "B")
+	require.NoError(t, err)
+
 	client.BaseURL = server.URL
 
 	res, err := client.ChangeResourceRecordSets("example.com", ChangeResourceRecordSetsRequest{})
@@ -83,7 +85,9 @@ func TestChangeResourceRecordSetsErrors(t *testing.T) {
 			server := runTestServer(test.responseBody, test.statusCode)
 			defer server.Close()
 
-			client := NewClient("", "")
+			client, err := NewClient("A", "B")
+			require.NoError(t, err)
+
 			client.BaseURL = server.URL
 
 			res, err := client.ChangeResourceRecordSets("example.com", ChangeResourceRecordSetsRequest{})
@@ -107,7 +111,9 @@ func TestGetChange(t *testing.T) {
 	server := runTestServer(responseBody, http.StatusOK)
 	defer server.Close()
 
-	client := NewClient("", "")
+	client, err := NewClient("A", "B")
+	require.NoError(t, err)
+
 	client.BaseURL = server.URL
 
 	res, err := client.GetChange("12345")
@@ -159,7 +165,9 @@ func TestGetChangeErrors(t *testing.T) {
 			server := runTestServer(test.responseBody, test.statusCode)
 			defer server.Close()
 
-			client := NewClient("", "")
+			client, err := NewClient("A", "B")
+			require.NoError(t, err)
+
 			client.BaseURL = server.URL
 
 			res, err := client.GetChange("12345")
diff --git a/providers/dns/nifcloud/nifcloud_test.go b/providers/dns/nifcloud/nifcloud_test.go
index f82b5bd6..d6602b88 100644
--- a/providers/dns/nifcloud/nifcloud_test.go
+++ b/providers/dns/nifcloud/nifcloud_test.go
@@ -9,44 +9,167 @@ import (
 )
 
 var (
-	nifcloudLiveTest  bool
-	nifcloudAccessKey string
-	nifcloudSecretKey string
-	nifcloudDomain    string
+	liveTest         bool
+	envTestAccessKey string
+	envTestSecretKey string
+	envTestDomain    string
 )
 
 func init() {
-	nifcloudAccessKey = os.Getenv("NIFCLOUD_ACCESS_KEY_ID")
-	nifcloudSecretKey = os.Getenv("NIFCLOUD_SECRET_ACCESS_KEY")
-	nifcloudDomain = os.Getenv("NIFCLOUD_DOMAIN")
+	envTestAccessKey = os.Getenv("NIFCLOUD_ACCESS_KEY_ID")
+	envTestSecretKey = os.Getenv("NIFCLOUD_SECRET_ACCESS_KEY")
+	envTestDomain = os.Getenv("NIFCLOUD_DOMAIN")
 
-	if len(nifcloudAccessKey) > 0 && len(nifcloudSecretKey) > 0 && len(nifcloudDomain) > 0 {
-		nifcloudLiveTest = true
+	if len(envTestAccessKey) > 0 && len(envTestSecretKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
-func TestLivenifcloudPresent(t *testing.T) {
-	if !nifcloudLiveTest {
+func restoreEnv() {
+	os.Setenv("NIFCLOUD_ACCESS_KEY_ID", envTestAccessKey)
+	os.Setenv("NIFCLOUD_SECRET_ACCESS_KEY", envTestSecretKey)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"NIFCLOUD_ACCESS_KEY_ID":     "123",
+				"NIFCLOUD_SECRET_ACCESS_KEY": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"NIFCLOUD_ACCESS_KEY_ID":     "",
+				"NIFCLOUD_SECRET_ACCESS_KEY": "",
+			},
+			expected: "nifcloud: some credentials information are missing: NIFCLOUD_ACCESS_KEY_ID,NIFCLOUD_SECRET_ACCESS_KEY",
+		},
+		{
+			desc: "missing access key",
+			envVars: map[string]string{
+				"NIFCLOUD_ACCESS_KEY_ID":     "",
+				"NIFCLOUD_SECRET_ACCESS_KEY": "456",
+			},
+			expected: "nifcloud: some credentials information are missing: NIFCLOUD_ACCESS_KEY_ID",
+		},
+		{
+			desc: "missing secret key",
+			envVars: map[string]string{
+				"NIFCLOUD_ACCESS_KEY_ID":     "123",
+				"NIFCLOUD_SECRET_ACCESS_KEY": "",
+			},
+			expected: "nifcloud: some credentials information are missing: NIFCLOUD_SECRET_ACCESS_KEY",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		accessKey string
+		secretKey string
+		expected  string
+	}{
+		{
+			desc:      "success",
+			accessKey: "123",
+			secretKey: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "nifcloud: credentials missing",
+		},
+		{
+			desc:      "missing api key",
+			secretKey: "456",
+			expected:  "nifcloud: credentials missing",
+		},
+		{
+			desc:      "missing secret key",
+			accessKey: "123",
+			expected:  "nifcloud: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("NIFCLOUD_ACCESS_KEY_ID")
+			os.Unsetenv("NIFCLOUD_SECRET_ACCESS_KEY")
+
+			config := NewDefaultConfig()
+			config.AccessKey = test.accessKey
+			config.SecretKey = test.secretKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(nifcloudDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
-func TestLivenifcloudCleanUp(t *testing.T) {
-	if !nifcloudLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(nifcloudDomain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/ns1/ns1_test.go b/providers/dns/ns1/ns1_test.go
index c40cc736..f1889ae5 100644
--- a/providers/dns/ns1/ns1_test.go
+++ b/providers/dns/ns1/ns1_test.go
@@ -10,21 +10,105 @@ import (
 )
 
 var (
-	liveTest bool
-	apiKey   string
-	domain   string
+	liveTest      bool
+	envTestAPIKey string
+	envTestDomain string
 )
 
 func init() {
-	apiKey = os.Getenv("NS1_API_KEY")
-	domain = os.Getenv("NS1_DOMAIN")
-	if len(apiKey) > 0 && len(domain) > 0 {
+	envTestAPIKey = os.Getenv("NS1_API_KEY")
+	envTestDomain = os.Getenv("NS1_DOMAIN")
+	if len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
 		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("NS1_API_KEY", apiKey)
+	os.Setenv("NS1_API_KEY", envTestAPIKey)
+}
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"NS1_API_KEY": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"NS1_API_KEY": "",
+			},
+			expected: "ns1: some credentials information are missing: NS1_API_KEY",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "ns1: credentials missing",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("NS1_API_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func Test_getAuthZone(t *testing.T) {
@@ -78,37 +162,16 @@ func Test_getAuthZone(t *testing.T) {
 	}
 }
 
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("NS1_API_KEY", "")
-
-	config := NewDefaultConfig()
-	config.APIKey = "123"
-
-	_, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-}
-
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("NS1_API_KEY", "")
-
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "ns1: some credentials information are missing: NS1_API_KEY")
-}
-
 func TestLivePresent(t *testing.T) {
 	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.APIKey = apiKey
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(domain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
@@ -117,14 +180,12 @@ func TestLiveCleanUp(t *testing.T) {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
-	config := NewDefaultConfig()
-	config.APIKey = apiKey
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(domain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/otc/mock.go b/providers/dns/otc/mock_test.go
similarity index 100%
rename from providers/dns/otc/mock.go
rename to providers/dns/otc/mock_test.go
diff --git a/providers/dns/otc/otc_test.go b/providers/dns/otc/otc_test.go
index 37a2983b..a83694c0 100644
--- a/providers/dns/otc/otc_test.go
+++ b/providers/dns/otc/otc_test.go
@@ -6,30 +6,30 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
 )
 
-type OTCDNSTestSuite struct {
+type TestSuite struct {
 	suite.Suite
 	Mock *DNSMock
 }
 
-func (s *OTCDNSTestSuite) TearDownSuite() {
+func (s *TestSuite) TearDownSuite() {
 	s.Mock.ShutdownServer()
 }
 
-func (s *OTCDNSTestSuite) SetupTest() {
+func (s *TestSuite) SetupTest() {
 	s.Mock = NewDNSMock(s.T())
 	s.Mock.Setup()
 	s.Mock.HandleAuthSuccessfully()
-
 }
 
-func TestOTCDNSTestSuite(t *testing.T) {
-	suite.Run(t, new(OTCDNSTestSuite))
+func TestTestSuite(t *testing.T) {
+	suite.Run(t, new(TestSuite))
 }
 
-func (s *OTCDNSTestSuite) createDNSProvider() (*DNSProvider, error) {
+func (s *TestSuite) createDNSProvider() (*DNSProvider, error) {
 	url := fmt.Sprintf("%s/v3/auth/token", s.Mock.Server.URL)
 
 	config := NewDefaultConfig()
@@ -42,7 +42,17 @@ func (s *OTCDNSTestSuite) createDNSProvider() (*DNSProvider, error) {
 	return NewDNSProviderConfig(config)
 }
 
-func (s *OTCDNSTestSuite) TestOTCDNSLoginEnv() {
+func (s *TestSuite) TestLogin() {
+	provider, err := s.createDNSProvider()
+	require.NoError(s.T(), err)
+
+	err = provider.loginRequest()
+	require.NoError(s.T(), err)
+	assert.Equal(s.T(), provider.baseURL, fmt.Sprintf("%s/v2", s.Mock.Server.URL))
+	assert.Equal(s.T(), fakeOTCToken, provider.token)
+}
+
+func (s *TestSuite) TestLoginEnv() {
 	defer os.Clearenv()
 
 	os.Setenv("OTC_DOMAIN_NAME", "unittest1")
@@ -52,7 +62,7 @@ func (s *OTCDNSTestSuite) TestOTCDNSLoginEnv() {
 	os.Setenv("OTC_IDENTITY_ENDPOINT", "unittest5")
 
 	provider, err := NewDNSProvider()
-	assert.Nil(s.T(), err)
+	require.NoError(s.T(), err)
 	assert.Equal(s.T(), provider.config.DomainName, "unittest1")
 	assert.Equal(s.T(), provider.config.UserName, "unittest2")
 	assert.Equal(s.T(), provider.config.Password, "unittest3")
@@ -62,60 +72,58 @@ func (s *OTCDNSTestSuite) TestOTCDNSLoginEnv() {
 	os.Setenv("OTC_IDENTITY_ENDPOINT", "")
 
 	provider, err = NewDNSProvider()
-	assert.Nil(s.T(), err)
+	require.NoError(s.T(), err)
 	assert.Equal(s.T(), provider.config.IdentityEndpoint, "https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens")
 }
 
-func (s *OTCDNSTestSuite) TestOTCDNSLoginEnvEmpty() {
+func (s *TestSuite) TestLoginEnvEmpty() {
 	defer os.Clearenv()
 
 	_, err := NewDNSProvider()
 	assert.EqualError(s.T(), err, "otc: some credentials information are missing: OTC_DOMAIN_NAME,OTC_USER_NAME,OTC_PASSWORD,OTC_PROJECT_NAME")
 }
 
-func (s *OTCDNSTestSuite) TestOTCDNSLogin() {
-	otcProvider, err := s.createDNSProvider()
+func (s *TestSuite) TestDNSProvider_Present() {
+	s.Mock.HandleListZonesSuccessfully()
+	s.Mock.HandleListRecordsetsSuccessfully()
+
+	provider, err := s.createDNSProvider()
+	require.NoError(s.T(), err)
 
-	assert.Nil(s.T(), err)
-	err = otcProvider.loginRequest()
-	assert.Nil(s.T(), err)
-	assert.Equal(s.T(), otcProvider.baseURL, fmt.Sprintf("%s/v2", s.Mock.Server.URL))
-	assert.Equal(s.T(), fakeOTCToken, otcProvider.token)
+	err = provider.Present("example.com", "", "foobar")
+	require.NoError(s.T(), err)
 }
 
-func (s *OTCDNSTestSuite) TestOTCDNSEmptyZone() {
+func (s *TestSuite) TestDNSProvider_Present_EmptyZone() {
 	s.Mock.HandleListZonesEmpty()
 	s.Mock.HandleListRecordsetsSuccessfully()
 
-	otcProvider, _ := s.createDNSProvider()
-	err := otcProvider.Present("example.com", "", "foobar")
-	assert.NotNil(s.T(), err)
-}
-
-func (s *OTCDNSTestSuite) TestOTCDNSEmptyRecordset() {
-	s.Mock.HandleListZonesSuccessfully()
-	s.Mock.HandleListRecordsetsEmpty()
+	provider, err := s.createDNSProvider()
+	require.NoError(s.T(), err)
 
-	otcProvider, _ := s.createDNSProvider()
-	err := otcProvider.CleanUp("example.com", "", "foobar")
+	err = provider.Present("example.com", "", "foobar")
 	assert.NotNil(s.T(), err)
 }
 
-func (s *OTCDNSTestSuite) TestOTCDNSPresent() {
+func (s *TestSuite) TestDNSProvider_CleanUp() {
 	s.Mock.HandleListZonesSuccessfully()
 	s.Mock.HandleListRecordsetsSuccessfully()
+	s.Mock.HandleDeleteRecordsetsSuccessfully()
+
+	provider, err := s.createDNSProvider()
+	require.NoError(s.T(), err)
 
-	otcProvider, _ := s.createDNSProvider()
-	err := otcProvider.Present("example.com", "", "foobar")
-	assert.Nil(s.T(), err)
+	err = provider.CleanUp("example.com", "", "foobar")
+	require.NoError(s.T(), err)
 }
 
-func (s *OTCDNSTestSuite) TestOTCDNSCleanup() {
+func (s *TestSuite) TestDNSProvider_CleanUp_EmptyRecordset() {
 	s.Mock.HandleListZonesSuccessfully()
-	s.Mock.HandleListRecordsetsSuccessfully()
-	s.Mock.HandleDeleteRecordsetsSuccessfully()
+	s.Mock.HandleListRecordsetsEmpty()
+
+	provider, err := s.createDNSProvider()
+	require.NoError(s.T(), err)
 
-	otcProvider, _ := s.createDNSProvider()
-	err := otcProvider.CleanUp("example.com", "", "foobar")
-	assert.Nil(s.T(), err)
+	err = provider.CleanUp("example.com", "", "foobar")
+	require.Error(s.T(), err)
 }
diff --git a/providers/dns/ovh/ovh_test.go b/providers/dns/ovh/ovh_test.go
index 2e6a3c8a..c6af2fe6 100644
--- a/providers/dns/ovh/ovh_test.go
+++ b/providers/dns/ovh/ovh_test.go
@@ -5,115 +5,225 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 var (
-	liveTest          bool
-	apiEndpoint       string
-	applicationKey    string
-	applicationSecret string
-	consumerKey       string
-	domain            string
+	liveTest                 bool
+	envTestAPIEndpoint       string
+	envTestApplicationKey    string
+	envTestApplicationSecret string
+	envTestConsumerKey       string
+	envTestDomain            string
 )
 
 func init() {
-	apiEndpoint = os.Getenv("OVH_ENDPOINT")
-	applicationKey = os.Getenv("OVH_APPLICATION_KEY")
-	applicationSecret = os.Getenv("OVH_APPLICATION_SECRET")
-	consumerKey = os.Getenv("OVH_CONSUMER_KEY")
-	liveTest = len(apiEndpoint) > 0 && len(applicationKey) > 0 && len(applicationSecret) > 0 && len(consumerKey) > 0
-}
+	envTestAPIEndpoint = os.Getenv("OVH_ENDPOINT")
+	envTestApplicationKey = os.Getenv("OVH_APPLICATION_KEY")
+	envTestApplicationSecret = os.Getenv("OVH_APPLICATION_SECRET")
+	envTestConsumerKey = os.Getenv("OVH_CONSUMER_KEY")
+	envTestDomain = os.Getenv("OVH_DOMAIN")
 
-func restoreEnv() {
-	os.Setenv("OVH_ENDPOINT", apiEndpoint)
-	os.Setenv("OVH_APPLICATION_KEY", applicationKey)
-	os.Setenv("OVH_APPLICATION_SECRET", applicationSecret)
-	os.Setenv("OVH_CONSUMER_KEY", consumerKey)
+	liveTest = len(envTestAPIEndpoint) > 0 && len(envTestApplicationKey) > 0 && len(envTestApplicationSecret) > 0 && len(envTestConsumerKey) > 0
 }
 
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("OVH_ENDPOINT", "ovh-eu")
-	os.Setenv("OVH_APPLICATION_KEY", "1234")
-	os.Setenv("OVH_APPLICATION_SECRET", "5678")
-	os.Setenv("OVH_CONSUMER_KEY", "abcde")
-
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
+func restoreEnv() {
+	os.Setenv("OVH_ENDPOINT", envTestAPIEndpoint)
+	os.Setenv("OVH_APPLICATION_KEY", envTestApplicationKey)
+	os.Setenv("OVH_APPLICATION_SECRET", envTestApplicationSecret)
+	os.Setenv("OVH_CONSUMER_KEY", envTestConsumerKey)
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-
+func TestNewDNSProvider(t *testing.T) {
 	testCases := []struct {
 		desc     string
 		envVars  map[string]string
 		expected string
 	}{
 		{
-			desc: "missing OVH_ENDPOINT",
+			desc: "success",
+			envVars: map[string]string{
+				"OVH_ENDPOINT":           "ovh-eu",
+				"OVH_APPLICATION_KEY":    "B",
+				"OVH_APPLICATION_SECRET": "C",
+				"OVH_CONSUMER_KEY":       "D",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"OVH_ENDPOINT":           "",
+				"OVH_APPLICATION_KEY":    "",
+				"OVH_APPLICATION_SECRET": "",
+				"OVH_CONSUMER_KEY":       "",
+			},
+			expected: "ovh: some credentials information are missing: OVH_ENDPOINT,OVH_APPLICATION_KEY,OVH_APPLICATION_SECRET,OVH_CONSUMER_KEY",
+		},
+		{
+			desc: "missing endpoint",
 			envVars: map[string]string{
 				"OVH_ENDPOINT":           "",
-				"OVH_APPLICATION_KEY":    "1234",
-				"OVH_APPLICATION_SECRET": "5678",
-				"OVH_CONSUMER_KEY":       "abcde",
+				"OVH_APPLICATION_KEY":    "B",
+				"OVH_APPLICATION_SECRET": "C",
+				"OVH_CONSUMER_KEY":       "D",
 			},
 			expected: "ovh: some credentials information are missing: OVH_ENDPOINT",
 		},
 		{
-			desc: "missing OVH_APPLICATION_KEY",
+			desc: "missing invalid endpoint",
+			envVars: map[string]string{
+				"OVH_ENDPOINT":           "foobar",
+				"OVH_APPLICATION_KEY":    "B",
+				"OVH_APPLICATION_SECRET": "C",
+				"OVH_CONSUMER_KEY":       "D",
+			},
+			expected: "ovh: unknown endpoint 'foobar', consider checking 'Endpoints' list of using an URL",
+		},
+		{
+			desc: "missing application key",
 			envVars: map[string]string{
 				"OVH_ENDPOINT":           "ovh-eu",
 				"OVH_APPLICATION_KEY":    "",
-				"OVH_APPLICATION_SECRET": "5678",
-				"OVH_CONSUMER_KEY":       "abcde",
+				"OVH_APPLICATION_SECRET": "C",
+				"OVH_CONSUMER_KEY":       "D",
 			},
 			expected: "ovh: some credentials information are missing: OVH_APPLICATION_KEY",
 		},
 		{
-			desc: "missing OVH_APPLICATION_SECRET",
+			desc: "missing application secret",
 			envVars: map[string]string{
 				"OVH_ENDPOINT":           "ovh-eu",
-				"OVH_APPLICATION_KEY":    "1234",
+				"OVH_APPLICATION_KEY":    "B",
 				"OVH_APPLICATION_SECRET": "",
-				"OVH_CONSUMER_KEY":       "abcde",
+				"OVH_CONSUMER_KEY":       "D",
 			},
 			expected: "ovh: some credentials information are missing: OVH_APPLICATION_SECRET",
 		},
 		{
-			desc: "missing OVH_CONSUMER_KEY",
+			desc: "missing consumer key",
 			envVars: map[string]string{
 				"OVH_ENDPOINT":           "ovh-eu",
-				"OVH_APPLICATION_KEY":    "1234",
-				"OVH_APPLICATION_SECRET": "5678",
+				"OVH_APPLICATION_KEY":    "B",
+				"OVH_APPLICATION_SECRET": "C",
 				"OVH_CONSUMER_KEY":       "",
 			},
 			expected: "ovh: some credentials information are missing: OVH_CONSUMER_KEY",
 		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+				require.NotNil(t, p.recordIDs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc              string
+		apiEndpoint       string
+		applicationKey    string
+		applicationSecret string
+		consumerKey       string
+		expected          string
+	}{
+		{
+			desc:              "success",
+			apiEndpoint:       "ovh-eu",
+			applicationKey:    "B",
+			applicationSecret: "C",
+			consumerKey:       "D",
+		},
 		{
-			desc: "all missing",
-			envVars: map[string]string{
-				"OVH_ENDPOINT":           "",
-				"OVH_APPLICATION_KEY":    "",
-				"OVH_APPLICATION_SECRET": "",
-				"OVH_CONSUMER_KEY":       "",
-			},
-			expected: "ovh: some credentials information are missing: OVH_ENDPOINT,OVH_APPLICATION_KEY,OVH_APPLICATION_SECRET,OVH_CONSUMER_KEY",
+			desc:     "missing credentials",
+			expected: "ovh: credentials missing",
+		},
+		{
+			desc:              "missing api endpoint",
+			apiEndpoint:       "",
+			applicationKey:    "B",
+			applicationSecret: "C",
+			consumerKey:       "D",
+			expected:          "ovh: credentials missing",
+		},
+		{
+			desc:              "missing invalid api endpoint",
+			apiEndpoint:       "foobar",
+			applicationKey:    "B",
+			applicationSecret: "C",
+			consumerKey:       "D",
+			expected:          "ovh: unknown endpoint 'foobar', consider checking 'Endpoints' list of using an URL",
+		},
+		{
+			desc:              "missing application key",
+			apiEndpoint:       "ovh-eu",
+			applicationKey:    "",
+			applicationSecret: "C",
+			consumerKey:       "D",
+			expected:          "ovh: credentials missing",
+		},
+		{
+			desc:              "missing application secret",
+			apiEndpoint:       "ovh-eu",
+			applicationKey:    "B",
+			applicationSecret: "",
+			consumerKey:       "D",
+			expected:          "ovh: credentials missing",
+		},
+		{
+			desc:              "missing consumer key",
+			apiEndpoint:       "ovh-eu",
+			applicationKey:    "B",
+			applicationSecret: "C",
+			consumerKey:       "",
+			expected:          "ovh: credentials missing",
 		},
 	}
 
 	for _, test := range testCases {
-		test := test
 		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("OVH_ENDPOINT")
+			os.Unsetenv("OVH_APPLICATION_KEY")
+			os.Unsetenv("OVH_APPLICATION_SECRET")
+			os.Unsetenv("OVH_CONSUMER_KEY")
 
-			for key, value := range test.envVars {
-				os.Setenv(key, value)
-			}
+			config := NewDefaultConfig()
+			config.APIEndpoint = test.apiEndpoint
+			config.ApplicationKey = test.applicationKey
+			config.ApplicationSecret = test.applicationSecret
+			config.ConsumerKey = test.consumerKey
 
-			_, err := NewDNSProvider()
-			assert.EqualError(t, err, test.expected)
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+				require.NotNil(t, p.recordIDs)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
 		})
 	}
 }
@@ -123,10 +233,11 @@ func TestLivePresent(t *testing.T) {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(domain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
@@ -135,11 +246,12 @@ func TestLiveCleanUp(t *testing.T) {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(domain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/pdns/pdns_test.go b/providers/dns/pdns/pdns_test.go
index 68d204d9..392b7099 100644
--- a/providers/dns/pdns/pdns_test.go
+++ b/providers/dns/pdns/pdns_test.go
@@ -5,90 +5,164 @@ import (
 	"os"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 var (
-	pdnsLiveTest bool
-	pdnsURL      *url.URL
-	pdnsURLStr   string
-	pdnsAPIKey   string
-	pdnsDomain   string
+	liveTest      bool
+	envTestAPIURL *url.URL
+	envTestAPIKey string
+	envTestDomain string
 )
 
 func init() {
-	pdnsURLStr = os.Getenv("PDNS_API_URL")
-	pdnsURL, _ = url.Parse(pdnsURLStr)
-	pdnsAPIKey = os.Getenv("PDNS_API_KEY")
-	pdnsDomain = os.Getenv("PDNS_DOMAIN")
-	if len(pdnsURLStr) > 0 && len(pdnsAPIKey) > 0 && len(pdnsDomain) > 0 {
-		pdnsLiveTest = true
+	envTestAPIURL, _ = url.Parse(os.Getenv("PDNS_API_URL"))
+	envTestAPIKey = os.Getenv("PDNS_API_KEY")
+	envTestDomain = os.Getenv("PDNS_DOMAIN")
+
+	if len(envTestAPIURL.String()) > 0 && len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("PDNS_API_URL", pdnsURLStr)
-	os.Setenv("PDNS_API_KEY", pdnsAPIKey)
-}
-
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("PDNS_API_URL", "")
-	os.Setenv("PDNS_API_KEY", "")
-
-	tmpURL, _ := url.Parse("http://localhost:8081")
-
-	config := NewDefaultConfig()
-	config.Host = tmpURL
-	config.APIKey = "123"
-
-	_, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-}
-
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("PDNS_API_URL", "http://localhost:8081")
-	os.Setenv("PDNS_API_KEY", "123")
-
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
+	os.Setenv("PDNS_API_URL", envTestAPIURL.String())
+	os.Setenv("PDNS_API_KEY", envTestAPIKey)
 }
 
-func TestNewDNSProviderMissingHostErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("PDNS_API_URL", "")
-	os.Setenv("PDNS_API_KEY", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"PDNS_API_KEY": "123",
+				"PDNS_API_URL": "http://example.com",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"PDNS_API_KEY": "",
+				"PDNS_API_URL": "",
+			},
+			expected: "pdns: some credentials information are missing: PDNS_API_KEY,PDNS_API_URL",
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"PDNS_API_KEY": "",
+				"PDNS_API_URL": "http://example.com",
+			},
+			expected: "pdns: some credentials information are missing: PDNS_API_KEY",
+		},
+		{
+			desc: "missing API URL",
+			envVars: map[string]string{
+				"PDNS_API_KEY": "123",
+				"PDNS_API_URL": "",
+			},
+			expected: "pdns: some credentials information are missing: PDNS_API_URL",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "pdns: some credentials information are missing: PDNS_API_URL")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingKeyErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("PDNS_API_URL", pdnsURLStr)
-	os.Setenv("PDNS_API_KEY", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		host     *url.URL
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+			host: func() *url.URL {
+				u, _ := url.Parse("http://example.com")
+				return u
+			}(),
+		},
+		{
+			desc:     "missing credentials",
+			expected: "pdns: API key missing",
+		},
+		{
+			desc:   "missing API key",
+			apiKey: "",
+			host: func() *url.URL {
+				u, _ := url.Parse("http://example.com")
+				return u
+			}(),
+			expected: "pdns: API key missing",
+		},
+		{
+			desc:     "missing host",
+			apiKey:   "123",
+			expected: "pdns: API URL missing",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "pdns: some credentials information are missing: PDNS_API_KEY,PDNS_API_URL")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("PDNS_API_KEY")
+			os.Unsetenv("PDNS_API_URL")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+			config.Host = test.host
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestPdnsPresentAndCleanup(t *testing.T) {
-	if !pdnsLiveTest {
+func TestLivePresentAndCleanup(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.Host = pdnsURL
-	config.APIKey = pdnsAPIKey
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(pdnsDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 
-	err = provider.CleanUp(pdnsDomain, "", "123d==")
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/rackspace/rackspace_test.go b/providers/dns/rackspace/rackspace_test.go
index ab214ab6..f4fa288f 100644
--- a/providers/dns/rackspace/rackspace_test.go
+++ b/providers/dns/rackspace/rackspace_test.go
@@ -15,45 +15,117 @@ import (
 )
 
 var (
-	rackspaceLiveTest bool
-	rackspaceUser     string
-	rackspaceAPIKey   string
-	rackspaceDomain   string
-	testAPIURL        string
+	liveTest      bool
+	envTestUser   string
+	envTestAPIKey string
+	envTestDomain string
 )
 
 func init() {
-	rackspaceUser = os.Getenv("RACKSPACE_USER")
-	rackspaceAPIKey = os.Getenv("RACKSPACE_API_KEY")
-	rackspaceDomain = os.Getenv("RACKSPACE_DOMAIN")
-	if len(rackspaceUser) > 0 && len(rackspaceAPIKey) > 0 && len(rackspaceDomain) > 0 {
-		rackspaceLiveTest = true
+	envTestUser = os.Getenv("RACKSPACE_USER")
+	envTestAPIKey = os.Getenv("RACKSPACE_API_KEY")
+	envTestDomain = os.Getenv("RACKSPACE_DOMAIN")
+
+	if len(envTestUser) > 0 && len(envTestAPIKey) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	config, tearDown := setupTest()
+	defer tearDown()
+
+	provider, err := NewDNSProviderConfig(config)
+	require.NoError(t, err)
+	assert.NotNil(t, provider.config)
+
+	assert.Equal(t, provider.token, "testToken", "The token should match")
+}
+
+func TestNewDNSProviderConfig_MissingCredErr(t *testing.T) {
+	_, err := NewDNSProviderConfig(NewDefaultConfig())
+	assert.EqualError(t, err, "rackspace: credentials missing")
+}
+
+func TestDNSProvider_Present(t *testing.T) {
+	config, tearDown := setupTest()
+	defer tearDown()
+
+	provider, err := NewDNSProviderConfig(config)
+
+	if assert.NoError(t, err) {
+		err = provider.Present("example.com", "token", "keyAuth")
+		require.NoError(t, err)
+	}
+}
+
+func TestDNSProvider_CleanUp(t *testing.T) {
+	config, tearDown := setupTest()
+	defer tearDown()
+
+	provider, err := NewDNSProviderConfig(config)
+
+	if assert.NoError(t, err) {
+		err = provider.CleanUp("example.com", "token", "keyAuth")
+		require.NoError(t, err)
+	}
+}
+
+func TestLiveNewDNSProvider_ValidEnv(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
 	}
+
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+	assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base")
 }
 
-func testRackspaceEnv() {
-	os.Setenv("RACKSPACE_USER", "testUser")
-	os.Setenv("RACKSPACE_API_KEY", "testKey")
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
+	}
+
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.Present(envTestDomain, "", "112233445566==")
+	require.NoError(t, err)
 }
 
-func liveRackspaceEnv() {
-	os.Setenv("RACKSPACE_USER", rackspaceUser)
-	os.Setenv("RACKSPACE_API_KEY", rackspaceAPIKey)
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
+	}
+
+	time.Sleep(time.Second * 15)
+
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.CleanUp(envTestDomain, "", "112233445566==")
+	require.NoError(t, err)
 }
 
-func startTestServers() (*httptest.Server, *httptest.Server) {
-	dnsAPI := httptest.NewServer(dnsMux())
-	dnsEndpoint := dnsAPI.URL + "/123456"
+func setupTest() (*Config, func()) {
+	apiURL, tearDown := startTestServers()
 
-	identityAPI := httptest.NewServer(identityHandler(dnsEndpoint))
-	testAPIURL = identityAPI.URL + "/"
+	config := NewDefaultConfig()
+	config.APIUser = "testUser"
+	config.APIKey = "testKey"
+	config.BaseURL = apiURL
 
-	return identityAPI, dnsAPI
+	return config, tearDown
 }
 
-func closeTestServers(identityAPI, dnsAPI *httptest.Server) {
-	identityAPI.Close()
-	dnsAPI.Close()
+func startTestServers() (string, func()) {
+	dnsAPI := httptest.NewServer(dnsHandler())
+	identityAPI := httptest.NewServer(identityHandler(dnsAPI.URL + "/123456"))
+
+	return identityAPI.URL + "/", func() {
+		identityAPI.Close()
+		dnsAPI.Close()
+	}
 }
 
 func identityHandler(dnsEndpoint string) http.Handler {
@@ -63,18 +135,20 @@ func identityHandler(dnsEndpoint string) http.Handler {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
 		}
+
 		resp, found := jsonMap[string(reqBody)]
 		if !found {
 			w.WriteHeader(http.StatusBadRequest)
 			return
 		}
+
 		resp = strings.Replace(resp, "https://dns.api.rackspacecloud.com/v1.0/123456", dnsEndpoint, 1)
 		w.WriteHeader(http.StatusOK)
 		fmt.Fprintf(w, resp)
 	})
 }
 
-func dnsMux() *http.ServeMux {
+func dnsHandler() *http.ServeMux {
 	mux := http.NewServeMux()
 
 	// Used by `getHostedZoneID()` finding `zoneID` "?name=example.com"
@@ -93,7 +167,7 @@ func dnsMux() *http.ServeMux {
 		case http.MethodPost:
 			reqBody, err := ioutil.ReadAll(r.Body)
 			if err != nil {
-				w.WriteHeader(http.StatusInternalServerError)
+				http.Error(w, err.Error(), http.StatusInternalServerError)
 				return
 			}
 			resp, found := jsonMap[string(reqBody)]
@@ -103,7 +177,7 @@ func dnsMux() *http.ServeMux {
 			}
 			w.WriteHeader(http.StatusAccepted)
 			fmt.Fprintf(w, resp)
-		// Used by `findTxtRecord()` finding `record.ID` "?type=TXT&name=_acme-challenge.example.com"
+			// Used by `findTxtRecord()` finding `record.ID` "?type=TXT&name=_acme-challenge.example.com"
 		case http.MethodGet:
 			if r.URL.Query().Get("type") == "TXT" && r.URL.Query().Get("name") == "_acme-challenge.example.com" {
 				w.WriteHeader(http.StatusOK)
@@ -112,7 +186,7 @@ func dnsMux() *http.ServeMux {
 			}
 			w.WriteHeader(http.StatusBadRequest)
 			return
-		// Used by `CleanUp()` deleting the TXT record "?id=445566"
+			// Used by `CleanUp()` deleting the TXT record "?id=445566"
 		case http.MethodDelete:
 			if r.URL.Query().Get("id") == "TXT-654321" {
 				w.WriteHeader(http.StatusOK)
@@ -131,104 +205,6 @@ func dnsMux() *http.ServeMux {
 	return mux
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	testRackspaceEnv()
-
-	_, err := NewDNSProviderConfig(&Config{})
-	assert.EqualError(t, err, "rackspace: credentials missing")
-}
-
-func TestOfflineRackspaceValid(t *testing.T) {
-	testRackspaceEnv()
-
-	config := NewDefaultConfig()
-	config.BaseURL = testAPIURL
-	config.APIKey = os.Getenv("RACKSPACE_API_KEY")
-	config.APIUser = os.Getenv("RACKSPACE_USER")
-
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
-
-	assert.Equal(t, provider.token, "testToken", "The token should match")
-}
-
-func TestOfflineRackspacePresent(t *testing.T) {
-	testRackspaceEnv()
-
-	config := NewDefaultConfig()
-	config.APIUser = os.Getenv("RACKSPACE_USER")
-	config.APIKey = os.Getenv("RACKSPACE_API_KEY")
-	config.BaseURL = testAPIURL
-
-	provider, err := NewDNSProviderConfig(config)
-
-	if assert.NoError(t, err) {
-		err = provider.Present("example.com", "token", "keyAuth")
-		require.NoError(t, err)
-	}
-}
-
-func TestOfflineRackspaceCleanUp(t *testing.T) {
-	testRackspaceEnv()
-
-	config := NewDefaultConfig()
-	config.APIUser = os.Getenv("RACKSPACE_USER")
-	config.APIKey = os.Getenv("RACKSPACE_API_KEY")
-	config.BaseURL = testAPIURL
-
-	provider, err := NewDNSProviderConfig(config)
-
-	if assert.NoError(t, err) {
-		err = provider.CleanUp("example.com", "token", "keyAuth")
-		require.NoError(t, err)
-	}
-}
-
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	if !rackspaceLiveTest {
-		t.Skip("skipping live test")
-	}
-
-	liveRackspaceEnv()
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-	assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base")
-}
-
-func TestRackspacePresent(t *testing.T) {
-	if !rackspaceLiveTest {
-		t.Skip("skipping live test")
-	}
-
-	liveRackspaceEnv()
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.Present(rackspaceDomain, "", "112233445566==")
-	require.NoError(t, err)
-}
-
-func TestRackspaceCleanUp(t *testing.T) {
-	if !rackspaceLiveTest {
-		t.Skip("skipping live test")
-	}
-
-	time.Sleep(time.Second * 15)
-
-	liveRackspaceEnv()
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.CleanUp(rackspaceDomain, "", "112233445566==")
-	require.NoError(t, err)
-}
-
-func TestMain(m *testing.M) {
-	identityAPI, dnsAPI := startTestServers()
-	defer closeTestServers(identityAPI, dnsAPI)
-	os.Exit(m.Run())
-}
-
 var jsonMap = map[string]string{
 	`{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"testUser","apiKey":"testKey"}}}`: `{"access":{"token":{"id":"testToken","expires":"1970-01-01T00:00:00.000Z","tenant":{"id":"123456","name":"123456"},"RAX-AUTH:authenticatedBy":["APIKEY"]},"serviceCatalog":[{"type":"rax:dns","endpoints":[{"publicURL":"https://dns.api.rackspacecloud.com/v1.0/123456","tenantId":"123456"}],"name":"cloudDNS"}],"user":{"id":"fakeUseID","name":"testUser"}}}`,
 	"zoneDetails": `{"domains":[{"name":"example.com","id":112233,"emailAddress":"hostmaster@example.com","updated":"1970-01-01T00:00:00.000+0000","created":"1970-01-01T00:00:00.000+0000"}],"totalEntries":1}`,
diff --git a/providers/dns/rfc2136/rfc2136_test.go b/providers/dns/rfc2136/rfc2136_test.go
index fc1ce7ce..a3625fe1 100644
--- a/providers/dns/rfc2136/rfc2136_test.go
+++ b/providers/dns/rfc2136/rfc2136_test.go
@@ -16,38 +16,33 @@ import (
 )
 
 var (
-	rfc2136TestDomain     = "123456789.www.example.com"
-	rfc2136TestKeyAuth    = "123d=="
-	rfc2136TestValue      = "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo"
-	rfc2136TestFqdn       = "_acme-challenge.123456789.www.example.com."
-	rfc2136TestZone       = "example.com."
-	rfc2136TestTTL        = 120
-	rfc2136TestTsigKey    = "example.com."
-	rfc2136TestTsigSecret = "IwBTJx9wrDp4Y1RyC3H0gA=="
+	envTestDomain     = "123456789.www.example.com"
+	envTestKeyAuth    = "123d=="
+	envTestValue      = "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo"
+	envTestFqdn       = "_acme-challenge.123456789.www.example.com."
+	envTestZone       = "example.com."
+	envTestTTL        = 120
+	envTestTsigKey    = "example.com."
+	envTestTsigSecret = "IwBTJx9wrDp4Y1RyC3H0gA=="
 )
 
 var reqChan = make(chan *dns.Msg, 10)
 
-func TestRFC2136CanaryLocalTestServer(t *testing.T) {
+func TestCanaryLocalTestServer(t *testing.T) {
 	acme.ClearFqdnCache()
 	dns.HandleFunc("example.com.", serverHandlerHello)
 	defer dns.HandleRemove("example.com.")
 
-	server, addrstr, err := runLocalDNSTestServer(false)
+	server, addr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer func() {
-		errS := server.Shutdown()
-		if errS != nil {
-			t.Log(errS)
-		}
-	}()
+	defer func() { _ = server.Shutdown() }()
 
 	c := new(dns.Client)
 	m := new(dns.Msg)
 
 	m.SetQuestion("example.com.", dns.TypeTXT)
 
-	r, _, err := c.Exchange(m, addrstr)
+	r, _, err := c.Exchange(m, addr)
 	require.NoError(t, err, "Failed to communicate with test server")
 	assert.Len(t, r.Extra, 1, "Failed to communicate with test server")
 
@@ -55,115 +50,95 @@ func TestRFC2136CanaryLocalTestServer(t *testing.T) {
 	assert.Equal(t, "Hello world", txt)
 }
 
-func TestRFC2136ServerSuccess(t *testing.T) {
+func TestServerSuccess(t *testing.T) {
 	acme.ClearFqdnCache()
-	dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
-	defer dns.HandleRemove(rfc2136TestZone)
+	dns.HandleFunc(envTestZone, serverHandlerReturnSuccess)
+	defer dns.HandleRemove(envTestZone)
 
-	server, addrstr, err := runLocalDNSTestServer(false)
+	server, addr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer func() {
-		errS := server.Shutdown()
-		if errS != nil {
-			t.Log(errS)
-		}
-	}()
+	defer func() { _ = server.Shutdown() }()
 
 	config := NewDefaultConfig()
-	config.Nameserver = addrstr
+	config.Nameserver = addr
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth)
+	err = provider.Present(envTestDomain, "", envTestKeyAuth)
 	require.NoError(t, err)
 }
 
-func TestRFC2136ServerError(t *testing.T) {
+func TestServerError(t *testing.T) {
 	acme.ClearFqdnCache()
-	dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr)
-	defer dns.HandleRemove(rfc2136TestZone)
+	dns.HandleFunc(envTestZone, serverHandlerReturnErr)
+	defer dns.HandleRemove(envTestZone)
 
-	server, addrstr, err := runLocalDNSTestServer(false)
+	server, addr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer func() {
-		errS := server.Shutdown()
-		if errS != nil {
-			t.Log(errS)
-		}
-	}()
+	defer func() { _ = server.Shutdown() }()
 
 	config := NewDefaultConfig()
-	config.Nameserver = addrstr
+	config.Nameserver = addr
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth)
+	err = provider.Present(envTestDomain, "", envTestKeyAuth)
 	require.Error(t, err)
 	if !strings.Contains(err.Error(), "NOTZONE") {
 		t.Errorf("Expected Present() to return an error with the 'NOTZONE' rcode string but it did not: %v", err)
 	}
 }
 
-func TestRFC2136TsigClient(t *testing.T) {
+func TestTsigClient(t *testing.T) {
 	acme.ClearFqdnCache()
-	dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
-	defer dns.HandleRemove(rfc2136TestZone)
+	dns.HandleFunc(envTestZone, serverHandlerReturnSuccess)
+	defer dns.HandleRemove(envTestZone)
 
-	server, addrstr, err := runLocalDNSTestServer(true)
+	server, addr, err := runLocalDNSTestServer(true)
 	require.NoError(t, err, "Failed to start test server")
-	defer func() {
-		errS := server.Shutdown()
-		if errS != nil {
-			t.Log(errS)
-		}
-	}()
+	defer func() { _ = server.Shutdown() }()
 
 	config := NewDefaultConfig()
-	config.Nameserver = addrstr
-	config.TSIGKey = rfc2136TestTsigKey
-	config.TSIGSecret = rfc2136TestTsigSecret
+	config.Nameserver = addr
+	config.TSIGKey = envTestTsigKey
+	config.TSIGSecret = envTestTsigSecret
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth)
+	err = provider.Present(envTestDomain, "", envTestKeyAuth)
 	require.NoError(t, err)
 }
 
-func TestRFC2136ValidUpdatePacket(t *testing.T) {
+func TestValidUpdatePacket(t *testing.T) {
 	acme.ClearFqdnCache()
-	dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest)
-	defer dns.HandleRemove(rfc2136TestZone)
+	dns.HandleFunc(envTestZone, serverHandlerPassBackRequest)
+	defer dns.HandleRemove(envTestZone)
 
-	server, addrstr, err := runLocalDNSTestServer(false)
+	server, addr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer func() {
-		errS := server.Shutdown()
-		if errS != nil {
-			t.Log(errS)
-		}
-	}()
+	defer func() { _ = server.Shutdown() }()
 
-	txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", rfc2136TestFqdn, rfc2136TestTTL, rfc2136TestValue))
+	txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", envTestFqdn, envTestTTL, envTestValue))
 	rrs := []dns.RR{txtRR}
 	m := new(dns.Msg)
-	m.SetUpdate(rfc2136TestZone)
+	m.SetUpdate(envTestZone)
 	m.RemoveRRset(rrs)
 	m.Insert(rrs)
-	expectstr := m.String()
+	expectStr := m.String()
 
 	expect, err := m.Pack()
 	require.NoError(t, err, "error packing")
 
 	config := NewDefaultConfig()
-	config.Nameserver = addrstr
+	config.Nameserver = addr
 
 	provider, err := NewDNSProviderConfig(config)
 	require.NoError(t, err)
 
-	err = provider.Present(rfc2136TestDomain, "", "1234d==")
+	err = provider.Present(envTestDomain, "", "1234d==")
 	require.NoError(t, err)
 
 	rcvMsg := <-reqChan
@@ -177,7 +152,7 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
 		if err := tmp.Unpack(actual); err != nil {
 			t.Fatalf("Error unpacking actual msg: %v", err)
 		}
-		t.Errorf("Expected msg:\n%s", expectstr)
+		t.Errorf("Expected msg:\n%s", expectStr)
 		t.Errorf("Actual msg:\n%v", tmp)
 	}
 }
@@ -187,9 +162,10 @@ func runLocalDNSTestServer(tsig bool) (*dns.Server, string, error) {
 	if err != nil {
 		return nil, "", err
 	}
+
 	server := &dns.Server{PacketConn: pc, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
 	if tsig {
-		server.TsigSecret = map[string]string{rfc2136TestTsigKey: rfc2136TestTsigSecret}
+		server.TsigSecret = map[string]string{envTestTsigKey: envTestTsigSecret}
 	}
 
 	waitLock := sync.Mutex{}
@@ -221,14 +197,14 @@ func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) {
 	m.SetReply(req)
 	if req.Opcode == dns.OpcodeQuery && req.Question[0].Qtype == dns.TypeSOA && req.Question[0].Qclass == dns.ClassINET {
 		// Return SOA to appease findZoneByFqdn()
-		soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", rfc2136TestZone, rfc2136TestTTL, rfc2136TestZone, rfc2136TestZone))
+		soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", envTestZone, envTestTTL, envTestZone, envTestZone))
 		m.Answer = []dns.RR{soaRR}
 	}
 
 	if t := req.IsTsig(); t != nil {
 		if w.TsigStatus() == nil {
 			// Validated
-			m.SetTsig(rfc2136TestZone, dns.HmacMD5, 300, time.Now().Unix())
+			m.SetTsig(envTestZone, dns.HmacMD5, 300, time.Now().Unix())
 		}
 	}
 
@@ -246,14 +222,14 @@ func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) {
 	m.SetReply(req)
 	if req.Opcode == dns.OpcodeQuery && req.Question[0].Qtype == dns.TypeSOA && req.Question[0].Qclass == dns.ClassINET {
 		// Return SOA to appease findZoneByFqdn()
-		soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", rfc2136TestZone, rfc2136TestTTL, rfc2136TestZone, rfc2136TestZone))
+		soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", envTestZone, envTestTTL, envTestZone, envTestZone))
 		m.Answer = []dns.RR{soaRR}
 	}
 
 	if t := req.IsTsig(); t != nil {
 		if w.TsigStatus() == nil {
 			// Validated
-			m.SetTsig(rfc2136TestZone, dns.HmacMD5, 300, time.Now().Unix())
+			m.SetTsig(envTestZone, dns.HmacMD5, 300, time.Now().Unix())
 		}
 	}
 
diff --git a/providers/dns/route53/route53_integration_test.go b/providers/dns/route53/route53_integration_test.go
index 68c076fb..eede6e6c 100644
--- a/providers/dns/route53/route53_integration_test.go
+++ b/providers/dns/route53/route53_integration_test.go
@@ -10,7 +10,7 @@ import (
 	"github.com/xenolf/lego/platform/config/env"
 )
 
-func TestRoute53TTL(t *testing.T) {
+func TestLiveTTL(t *testing.T) {
 	config, err := env.Get("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION", "R53_DOMAIN")
 	if err != nil {
 		t.Skip(err.Error())
@@ -19,19 +19,19 @@ func TestRoute53TTL(t *testing.T) {
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	r53Domain := config["R53_DOMAIN"]
+	domain := config["R53_DOMAIN"]
 
-	err = provider.Present(r53Domain, "foo", "bar")
+	err = provider.Present(domain, "foo", "bar")
 	require.NoError(t, err)
 
 	// we need a separate R53 client here as the one in the DNS provider is unexported.
-	fqdn := "_acme-challenge." + r53Domain + "."
+	fqdn := "_acme-challenge." + domain + "."
 	sess, err := session.NewSession()
 	require.NoError(t, err)
 	svc := route53.New(sess)
 
 	defer func() {
-		errC := provider.CleanUp(r53Domain, "foo", "bar")
+		errC := provider.CleanUp(domain, "foo", "bar")
 		if errC != nil {
 			t.Log(errC)
 		}
@@ -52,5 +52,5 @@ func TestRoute53TTL(t *testing.T) {
 		}
 	}
 
-	t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", r53Domain)
+	t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", domain)
 }
diff --git a/providers/dns/route53/route53_test.go b/providers/dns/route53/route53_test.go
index 4f2a0410..cc840685 100644
--- a/providers/dns/route53/route53_test.go
+++ b/providers/dns/route53/route53_test.go
@@ -15,39 +15,39 @@ import (
 )
 
 var (
-	r53AwsSecretAccessKey string
-	r53AwsAccessKeyID     string
-	r53AwsRegion          string
-	r53AwsHostedZoneID    string
-
-	r53AwsMaxRetries         string
-	r53AwsTTL                string
-	r53AwsPropagationTimeout string
-	r53AwsPollingInterval    string
+	envTestAwsSecretAccessKey string
+	envTestAwsAccessKeyID     string
+	envTestAwsRegion          string
+	envTestAwsHostedZoneID    string
+
+	envTestAwsMaxRetries         string
+	envTestAwsTTL                string
+	envTestAwsPropagationTimeout string
+	envTestAwsPollingInterval    string
 )
 
 func init() {
-	r53AwsAccessKeyID = os.Getenv("AWS_ACCESS_KEY_ID")
-	r53AwsSecretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
-	r53AwsRegion = os.Getenv("AWS_REGION")
-	r53AwsHostedZoneID = os.Getenv("AWS_HOSTED_ZONE_ID")
-
-	r53AwsMaxRetries = os.Getenv("AWS_MAX_RETRIES")
-	r53AwsTTL = os.Getenv("AWS_TTL")
-	r53AwsPropagationTimeout = os.Getenv("AWS_PROPAGATION_TIMEOUT")
-	r53AwsPollingInterval = os.Getenv("AWS_POLLING_INTERVAL")
+	envTestAwsAccessKeyID = os.Getenv("AWS_ACCESS_KEY_ID")
+	envTestAwsSecretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
+	envTestAwsRegion = os.Getenv("AWS_REGION")
+	envTestAwsHostedZoneID = os.Getenv("AWS_HOSTED_ZONE_ID")
+
+	envTestAwsMaxRetries = os.Getenv("AWS_MAX_RETRIES")
+	envTestAwsTTL = os.Getenv("AWS_TTL")
+	envTestAwsPropagationTimeout = os.Getenv("AWS_PROPAGATION_TIMEOUT")
+	envTestAwsPollingInterval = os.Getenv("AWS_POLLING_INTERVAL")
 }
 
 func restoreEnv() {
-	os.Setenv("AWS_ACCESS_KEY_ID", r53AwsAccessKeyID)
-	os.Setenv("AWS_SECRET_ACCESS_KEY", r53AwsSecretAccessKey)
-	os.Setenv("AWS_REGION", r53AwsRegion)
-	os.Setenv("AWS_HOSTED_ZONE_ID", r53AwsHostedZoneID)
-
-	os.Setenv("AWS_MAX_RETRIES", r53AwsMaxRetries)
-	os.Setenv("AWS_TTL", r53AwsTTL)
-	os.Setenv("AWS_PROPAGATION_TIMEOUT", r53AwsPropagationTimeout)
-	os.Setenv("AWS_POLLING_INTERVAL", r53AwsPollingInterval)
+	os.Setenv("AWS_ACCESS_KEY_ID", envTestAwsAccessKeyID)
+	os.Setenv("AWS_SECRET_ACCESS_KEY", envTestAwsSecretAccessKey)
+	os.Setenv("AWS_REGION", envTestAwsRegion)
+	os.Setenv("AWS_HOSTED_ZONE_ID", envTestAwsHostedZoneID)
+
+	os.Setenv("AWS_MAX_RETRIES", envTestAwsMaxRetries)
+	os.Setenv("AWS_TTL", envTestAwsTTL)
+	os.Setenv("AWS_PROPAGATION_TIMEOUT", envTestAwsPropagationTimeout)
+	os.Setenv("AWS_POLLING_INTERVAL", envTestAwsPollingInterval)
 }
 
 func cleanEnv() {
@@ -62,7 +62,7 @@ func cleanEnv() {
 	os.Unsetenv("AWS_POLLING_INTERVAL")
 }
 
-func makeRoute53Provider(ts *httptest.Server) *DNSProvider {
+func makeTestProvider(ts *httptest.Server) *DNSProvider {
 	config := &aws.Config{
 		Credentials: credentials.NewStaticCredentials("abc", "123", " "),
 		Endpoint:    aws.String(ts.URL),
@@ -93,7 +93,7 @@ func Test_loadCredentials_FromEnv(t *testing.T) {
 	require.NoError(t, err)
 
 	value, err := sess.Config.Credentials.Get()
-	assert.NoError(t, err, "Expected credentials to be set from environment")
+	require.NoError(t, err, "Expected credentials to be set from environment")
 
 	expected := credentials.Value{
 		AccessKeyID:     "123",
@@ -123,10 +123,10 @@ func Test_getHostedZoneID_FromEnv(t *testing.T) {
 	os.Setenv("AWS_HOSTED_ZONE_ID", expectedZoneID)
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	hostedZoneID, err := provider.getHostedZoneID("whatever")
-	assert.NoError(t, err, "HostedZoneID")
+	require.NoError(t, err, "HostedZoneID")
 
 	assert.Equal(t, expectedZoneID, hostedZoneID)
 }
@@ -181,7 +181,7 @@ func TestNewDefaultConfig(t *testing.T) {
 	}
 }
 
-func TestRoute53Present(t *testing.T) {
+func TestDNSProvider_Present(t *testing.T) {
 	mockResponses := MockResponseMap{
 		"/2013-04-01/hostedzonesbyname":         {StatusCode: 200, Body: ListHostedZonesByNameResponse},
 		"/2013-04-01/hostedzone/ABCDEFG/rrset/": {StatusCode: 200, Body: ChangeResourceRecordSetsResponse},
@@ -195,11 +195,11 @@ func TestRoute53Present(t *testing.T) {
 	ts := newMockServer(t, mockResponses)
 	defer ts.Close()
 
-	provider := makeRoute53Provider(ts)
+	provider := makeTestProvider(ts)
 
 	domain := "example.com"
 	keyAuth := "123456d=="
 
 	err := provider.Present(domain, "", keyAuth)
-	assert.NoError(t, err, "Expected Present to return no error")
+	require.NoError(t, err, "Expected Present to return no error")
 }
diff --git a/providers/dns/sakuracloud/sakuracloud_test.go b/providers/dns/sakuracloud/sakuracloud_test.go
index d8713a54..5de74b0c 100644
--- a/providers/dns/sakuracloud/sakuracloud_test.go
+++ b/providers/dns/sakuracloud/sakuracloud_test.go
@@ -5,121 +5,171 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	"github.com/xenolf/lego/acme"
 )
 
 var (
-	sakuracloudLiveTest     bool
-	sakuracloudAccessToken  string
-	sakuracloudAccessSecret string
-	sakuracloudDomain       string
+	liveTest            bool
+	envTestAccessToken  string
+	envTestAccessSecret string
+	envTestDomain       string
 )
 
 func init() {
-	sakuracloudAccessToken = os.Getenv("SAKURACLOUD_ACCESS_TOKEN")
-	sakuracloudAccessSecret = os.Getenv("SAKURACLOUD_ACCESS_TOKEN_SECRET")
-	sakuracloudDomain = os.Getenv("SAKURACLOUD_DOMAIN")
+	envTestAccessToken = os.Getenv("SAKURACLOUD_ACCESS_TOKEN")
+	envTestAccessSecret = os.Getenv("SAKURACLOUD_ACCESS_TOKEN_SECRET")
+	envTestDomain = os.Getenv("SAKURACLOUD_DOMAIN")
 
-	if len(sakuracloudAccessToken) > 0 && len(sakuracloudAccessSecret) > 0 && len(sakuracloudDomain) > 0 {
-		sakuracloudLiveTest = true
+	if len(envTestAccessToken) > 0 && len(envTestAccessSecret) > 0 && len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("SAKURACLOUD_ACCESS_TOKEN", sakuracloudAccessToken)
-	os.Setenv("SAKURACLOUD_ACCESS_TOKEN_SECRET", sakuracloudAccessSecret)
+	os.Setenv("SAKURACLOUD_ACCESS_TOKEN", envTestAccessToken)
+	os.Setenv("SAKURACLOUD_ACCESS_TOKEN_SECRET", envTestAccessSecret)
 }
 
-//
-// NewDNSProvider
-//
-
-func TestNewDNSProviderValid(t *testing.T) {
-	defer restoreEnv()
-
-	os.Setenv("SAKURACLOUD_ACCESS_TOKEN", "123")
-	os.Setenv("SAKURACLOUD_ACCESS_TOKEN_SECRET", "456")
-	provider, err := NewDNSProvider()
-
-	assert.NotNil(t, provider)
-	assert.Equal(t, acme.UserAgent, provider.client.UserAgent)
-	require.NoError(t, err)
-}
-
-func TestNewDNSProviderInvalidWithMissingAccessToken(t *testing.T) {
-	defer restoreEnv()
-
-	os.Setenv("SAKURACLOUD_ACCESS_TOKEN", "")
-	provider, err := NewDNSProvider()
-
-	assert.Nil(t, provider)
-	assert.EqualError(t, err, "sakuracloud: some credentials information are missing: SAKURACLOUD_ACCESS_TOKEN,SAKURACLOUD_ACCESS_TOKEN_SECRET")
-}
-
-//
-// NewDNSProviderCredentials
-//
-
-func TestNewDNSProviderCredentialsValid(t *testing.T) {
-	config := NewDefaultConfig()
-	config.Token = "123"
-	config.Secret = "456"
-
-	provider, err := NewDNSProviderConfig(config)
-	require.NoError(t, err)
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"SAKURACLOUD_ACCESS_TOKEN":        "123",
+				"SAKURACLOUD_ACCESS_TOKEN_SECRET": "456",
+			},
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				"SAKURACLOUD_ACCESS_TOKEN":        "",
+				"SAKURACLOUD_ACCESS_TOKEN_SECRET": "",
+			},
+			expected: "sakuracloud: some credentials information are missing: SAKURACLOUD_ACCESS_TOKEN,SAKURACLOUD_ACCESS_TOKEN_SECRET",
+		},
+		{
+			desc: "missing access token",
+			envVars: map[string]string{
+				"SAKURACLOUD_ACCESS_TOKEN":        "",
+				"SAKURACLOUD_ACCESS_TOKEN_SECRET": "456",
+			},
+			expected: "sakuracloud: some credentials information are missing: SAKURACLOUD_ACCESS_TOKEN",
+		},
+		{
+			desc: "missing token secret",
+			envVars: map[string]string{
+				"SAKURACLOUD_ACCESS_TOKEN":        "123",
+				"SAKURACLOUD_ACCESS_TOKEN_SECRET": "",
+			},
+			expected: "sakuracloud: some credentials information are missing: SAKURACLOUD_ACCESS_TOKEN_SECRET",
+		},
+	}
 
-	assert.NotNil(t, provider)
-	assert.Equal(t, acme.UserAgent, provider.client.UserAgent)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderCredentialsInvalidWithMissingAccessToken(t *testing.T) {
-	config := NewDefaultConfig()
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		token    string
+		secret   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			token:  "123",
+			secret: "456",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "sakuracloud: AccessToken is missing",
+		},
+		{
+			desc:     "missing token",
+			secret:   "456",
+			expected: "sakuracloud: AccessToken is missing",
+		},
+		{
+			desc:     "missing secret",
+			token:    "123",
+			expected: "sakuracloud: AccessSecret is missing",
+		},
+	}
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.Nil(t, provider)
-	assert.EqualError(t, err, "sakuracloud: AccessToken is missing")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("SAKURACLOUD_ACCESS_TOKEN")
+			os.Unsetenv("SAKURACLOUD_ACCESS_TOKEN_SECRET")
+
+			config := NewDefaultConfig()
+			config.Token = test.token
+			config.Secret = test.secret
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-//
-// Present
-//
-
-func TestLiveSakuraCloudPresent(t *testing.T) {
-	if !sakuracloudLiveTest {
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	config := NewDefaultConfig()
-	config.Token = sakuracloudAccessToken
-	config.Secret = sakuracloudAccessSecret
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(sakuracloudDomain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
-//
-// Cleanup
-//
-
-func TestLiveSakuraCloudCleanUp(t *testing.T) {
-	if !sakuracloudLiveTest {
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
-	config := NewDefaultConfig()
-	config.Token = sakuracloudAccessToken
-	config.Secret = sakuracloudAccessSecret
-
-	provider, err := NewDNSProviderConfig(config)
+	restoreEnv()
+	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(sakuracloudDomain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
diff --git a/providers/dns/stackpath/stackpath_test.go b/providers/dns/stackpath/stackpath_test.go
index 9ee42dc2..54ecd47d 100644
--- a/providers/dns/stackpath/stackpath_test.go
+++ b/providers/dns/stackpath/stackpath_test.go
@@ -13,58 +13,32 @@ import (
 )
 
 var (
-	stackpathLiveTest     bool
-	stackpathClientID     string
-	stackpathClientSecret string
-	stackpathStackID      string
-	stackpathDomain       string
+	liveTest            bool
+	envTestClientID     string
+	envTestClientSecret string
+	envTestStackID      string
+	envTestDomain       string
 )
 
 func init() {
-	stackpathClientID = os.Getenv("STACKPATH_CLIENT_ID")
-	stackpathClientSecret = os.Getenv("STACKPATH_CLIENT_SECRET")
-	stackpathStackID = os.Getenv("STACKPATH_STACK_ID")
-	stackpathDomain = os.Getenv("STACKPATH_DOMAIN")
-
-	if len(stackpathClientID) > 0 &&
-		len(stackpathClientSecret) > 0 &&
-		len(stackpathStackID) > 0 &&
-		len(stackpathDomain) > 0 {
-		stackpathLiveTest = true
+	envTestClientID = os.Getenv("STACKPATH_CLIENT_ID")
+	envTestClientSecret = os.Getenv("STACKPATH_CLIENT_SECRET")
+	envTestStackID = os.Getenv("STACKPATH_STACK_ID")
+	envTestDomain = os.Getenv("STACKPATH_DOMAIN")
+
+	if len(envTestClientID) > 0 &&
+		len(envTestClientSecret) > 0 &&
+		len(envTestStackID) > 0 &&
+		len(envTestDomain) > 0 {
+		liveTest = true
 	}
 }
 
 func restoreEnv() {
-	os.Setenv("STACKPATH_CLIENT_ID", stackpathClientID)
-	os.Setenv("STACKPATH_CLIENT_SECRET", stackpathClientSecret)
-	os.Setenv("STACKPATH_STACK_ID", stackpathStackID)
-	os.Setenv("STACKPATH_DOMAIN", stackpathDomain)
-}
-
-func TestLivePresent(t *testing.T) {
-	if !stackpathLiveTest {
-		t.Skip("skipping live test")
-	}
-
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.Present(stackpathDomain, "", "123d==")
-	require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
-	if !stackpathLiveTest {
-		t.Skip("skipping live test")
-	}
-
-	time.Sleep(time.Second * 1)
-
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.CleanUp(stackpathDomain, "", "123d==")
-	require.NoError(t, err)
+	os.Setenv("STACKPATH_CLIENT_ID", envTestClientID)
+	os.Setenv("STACKPATH_CLIENT_SECRET", envTestClientSecret)
+	os.Setenv("STACKPATH_STACK_ID", envTestStackID)
+	os.Setenv("STACKPATH_DOMAIN", envTestDomain)
 }
 
 func TestNewDNSProvider(t *testing.T) {
@@ -133,7 +107,7 @@ func TestNewDNSProvider(t *testing.T) {
 			p, err := NewDNSProvider()
 
 			if len(test.expected) == 0 {
-				assert.NoError(t, err)
+				require.NoError(t, err)
 				assert.NotNil(t, p)
 			} else {
 				require.EqualError(t, err, test.expected)
@@ -313,3 +287,31 @@ func TestDNSProvider_getZones(t *testing.T) {
 
 	assert.Equal(t, expected, zone)
 }
+
+func TestLivePresent(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
+	}
+
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.Present(envTestDomain, "", "123d==")
+	require.NoError(t, err)
+}
+
+func TestLiveCleanUp(t *testing.T) {
+	if !liveTest {
+		t.Skip("skipping live test")
+	}
+
+	restoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
+	require.NoError(t, err)
+}
diff --git a/providers/dns/vegadns/vegadns_test.go b/providers/dns/vegadns/vegadns_test.go
index 257f2dda..50af3172 100644
--- a/providers/dns/vegadns/vegadns_test.go
+++ b/providers/dns/vegadns/vegadns_test.go
@@ -103,14 +103,14 @@ var jsonMap = map[string]string{
 
 type muxCallback func() *http.ServeMux
 
-func TestVegaDNSNewDNSProviderFail(t *testing.T) {
+func TestNewDNSProvider_Fail(t *testing.T) {
 	os.Setenv("VEGADNS_URL", "")
 	_, err := NewDNSProvider()
 	assert.Error(t, err, "VEGADNS_URL env missing")
 }
 
-func TestVegaDNSTimeoutSuccess(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxSuccess)
+func TestDNSProvider_TimeoutSuccess(t *testing.T) {
+	ts, err := startTestServer(muxSuccess)
 	require.NoError(t, err)
 
 	defer ts.Close()
@@ -132,16 +132,16 @@ func TestDNSProvider_Present(t *testing.T) {
 	}{
 		{
 			desc:     "Success",
-			callback: vegaDNSMuxSuccess,
+			callback: muxSuccess,
 		},
 		{
 			desc:          "FailToFindZone",
-			callback:      vegaDNSMuxFailToFindZone,
+			callback:      muxFailToFindZone,
 			expectedError: "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in Present: Unable to find auth zone for fqdn _acme-challenge.example.com",
 		},
 		{
 			desc:          "FailToCreateTXT",
-			callback:      vegaDNSMuxFailToCreateTXT,
+			callback:      muxFailToCreateTXT,
 			expectedError: "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: ",
 		},
 	}
@@ -175,16 +175,16 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 	}{
 		{
 			desc:     "Success",
-			callback: vegaDNSMuxSuccess,
+			callback: muxSuccess,
 		},
 		{
 			desc:          "FailToFindZone",
-			callback:      vegaDNSMuxFailToFindZone,
+			callback:      muxFailToFindZone,
 			expectedError: "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in CleanUp: Unable to find auth zone for fqdn _acme-challenge.example.com",
 		},
 		{
 			desc:          "FailToGetRecordID",
-			callback:      vegaDNSMuxFailToGetRecordID,
+			callback:      muxFailToGetRecordID,
 			expectedError: "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: ",
 		},
 	}
@@ -210,7 +210,7 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 	}
 }
 
-func vegaDNSMuxSuccess() *http.ServeMux {
+func muxSuccess() *http.ServeMux {
 	mux := http.NewServeMux()
 
 	mux.HandleFunc("/1.0/token", func(w http.ResponseWriter, r *http.Request) {
@@ -268,7 +268,7 @@ func vegaDNSMuxSuccess() *http.ServeMux {
 	return mux
 }
 
-func vegaDNSMuxFailToFindZone() *http.ServeMux {
+func muxFailToFindZone() *http.ServeMux {
 	mux := http.NewServeMux()
 
 	mux.HandleFunc("/1.0/token", func(w http.ResponseWriter, r *http.Request) {
@@ -288,7 +288,7 @@ func vegaDNSMuxFailToFindZone() *http.ServeMux {
 	return mux
 }
 
-func vegaDNSMuxFailToCreateTXT() *http.ServeMux {
+func muxFailToCreateTXT() *http.ServeMux {
 	mux := http.NewServeMux()
 
 	mux.HandleFunc("/1.0/token", func(w http.ResponseWriter, r *http.Request) {
@@ -330,7 +330,7 @@ func vegaDNSMuxFailToCreateTXT() *http.ServeMux {
 	return mux
 }
 
-func vegaDNSMuxFailToGetRecordID() *http.ServeMux {
+func muxFailToGetRecordID() *http.ServeMux {
 	mux := http.NewServeMux()
 
 	mux.HandleFunc("/1.0/token", func(w http.ResponseWriter, r *http.Request) {
diff --git a/providers/dns/vultr/vultr_test.go b/providers/dns/vultr/vultr_test.go
index 0f045c01..2d7fe58c 100644
--- a/providers/dns/vultr/vultr_test.go
+++ b/providers/dns/vultr/vultr_test.go
@@ -5,40 +5,108 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 var (
-	liveTest bool
-	apiKey   string
-	domain   string
+	liveTest      bool
+	envTestAPIKey string
+	envTestDomain string
 )
 
 func init() {
-	apiKey = os.Getenv("VULTR_API_KEY")
-	domain = os.Getenv("VULTR_TEST_DOMAIN")
-	liveTest = len(apiKey) > 0 && len(domain) > 0
+	envTestAPIKey = os.Getenv("VULTR_API_KEY")
+	envTestDomain = os.Getenv("VULTR_TEST_DOMAIN")
+
+	liveTest = len(envTestAPIKey) > 0 && len(envTestDomain) > 0
 }
 
 func restoreEnv() {
-	os.Setenv("VULTR_API_KEY", apiKey)
+	os.Setenv("VULTR_API_KEY", envTestAPIKey)
 }
 
-func TestNewDNSProviderValidEnv(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("VULTR_API_KEY", "123")
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				"VULTR_API_KEY": "123",
+			},
+		},
+		{
+			desc: "missing api key",
+			envVars: map[string]string{
+				"VULTR_API_KEY": "",
+			},
+			expected: "vultr: some credentials information are missing: VULTR_API_KEY",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	require.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			for key, value := range test.envVars {
+				if len(value) == 0 {
+					os.Unsetenv(key)
+				} else {
+					os.Setenv(key, value)
+				}
+			}
+
+			p, err := NewDNSProvider()
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
-func TestNewDNSProviderMissingCredErr(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("VULTR_API_KEY", "")
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		apiKey   string
+		expected string
+	}{
+		{
+			desc:   "success",
+			apiKey: "123",
+		},
+		{
+			desc:     "missing credentials",
+			expected: "vultr: credentials missing",
+		},
+	}
 
-	_, err := NewDNSProvider()
-	assert.EqualError(t, err, "vultr: some credentials information are missing: VULTR_API_KEY")
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer restoreEnv()
+			os.Unsetenv("VULTR_API_KEY")
+
+			config := NewDefaultConfig()
+			config.APIKey = test.apiKey
+
+			p, err := NewDNSProviderConfig(config)
+
+			if len(test.expected) == 0 {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+				require.NotNil(t, p.client)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
 }
 
 func TestLivePresent(t *testing.T) {
@@ -46,10 +114,11 @@ func TestLivePresent(t *testing.T) {
 		t.Skip("skipping live test")
 	}
 
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(domain, "", "123d==")
+	err = provider.Present(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }
 
@@ -58,11 +127,12 @@ func TestLiveCleanUp(t *testing.T) {
 		t.Skip("skipping live test")
 	}
 
-	time.Sleep(time.Second * 1)
-
+	restoreEnv()
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.CleanUp(domain, "", "123d==")
+	time.Sleep(1 * time.Second)
+
+	err = provider.CleanUp(envTestDomain, "", "123d==")
 	require.NoError(t, err)
 }