testroutines

package
v0.0.0-...-d26d7fe Latest Latest
Warning

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

Go to latest
Published: Dec 20, 2024 License: MIT Imports: 10 Imported by: 0

README

Package testroutines

Purpose

This package provides base test case for creating Test Suites.

Description

Most common connector methods can be tested using:

  • testroutines.Read - Read
  • testroutines.Write - Write
  • testroutines.Metadata - ListObjectMetadata
  • testroutines.Delete - Delete

They can be used as a template to declare your unique test case type. The main difference among them is

  • input type
  • output type
  • tested method

Below is the example of the run method:

// Declaration
func (r Read) Run(t *testing.T, builder ConnectorBuilder[connectors.ReadConnector]) {
t.Helper()
conn := builder.Build(t, r.Name) // builder will return Connector of certain type
readParams := prepareReadParams(r.Server.URL, r.Input) // substitute BaseURL with MockServerURL
output, err := conn.Read(context.Background(), readParams) // select a method that you want to test and pass input
ReadType(r).Validate(t, err, output) // invoke TestCase[InputType,OutputType].Validate(...)
}

// Example calling method
tt.Run(t, func () (connectors.ReadConnector, error) {
return constructTestConnector(tt.Server.URL)
})
TestCase

A Test case consists of:

  • InputType: captures all inputs to the tested method. Inside the Run method, it is wired and passed as arguments required by the method.
  • OutputType: represents the result of a successful method execution, which is then compared against TestCase.Expected using TestCase.Comparatorfor equality check (or deep equal if none specified).

A test case can also include TestCase.ExpectedErrs, which ensures that all expected errors are present in the returned error (checked as a subset, not strict equality).

type Read TestCase[common.ReadParams, *common.ReadResult]

func TestRead(t *testing.T) {
  t.Parallel()
  
  // Common test setup
  // ...

  // Suite definition
  tests := []testroutines.Read{
    {
      Name:         "Title of the test",
      Input:        &common.ReadParams{} // This object represents `InputType`
      Server:       mockserver.Dummy(),  // Configure mock server to respond on requests.
      Comparator:   func (baseURL string, actual, expected *common.ReadResult) bool {
        return true // Custom function to compare expected vs given `OutputType`.
      },
      ExpectedErrs: []error{common.ErrMissingObjects}, // List of expected errors to be inside error object 
      Expected:     &common.ReadResult{} // This object represents `OutputType`
    },
    
    // ... other test cases ...

  }
  
  // Running tests in the loop
  // ...
}
Comparator

In most cases, an exact comparison can make test cases overly large and noisy. Comparing just a few objects or a subset of fields is often sufficient. For example:

{
    Name: "Incremental read of conversations via search",
    Input: common.ReadParams{...},
    Server: mockserver.Conditional{...}.Server(),
    Comparator: testroutines.ComparatorSubsetRead,
    Expected: &common.ReadResult{
        Rows: 1,
        Data: []common.ReadResultRow{{
            Fields: map[string]any{
                "id":    "5",
                "state": "open",
                "title": "What is return policy?",
            },
            Raw: map[string]any{
                "ai_agent_participated": false,
            },
        }},
        NextPage: testroutines.URLTestServer + "/conversations/search?starting_after=WzE3MjY3NTIxNDUwMDAsNSwyXQ==",
        Done:     false,
    },
    ExpectedErrs: nil,
}

This approach ensures the test is concise while still validating the critical aspects of the behavior. It's important to note that any reference to the original connector BaseURL should be replaced with testroutines.URLTestServer either in ReadResult or ReadParams. During runtime, this value will be correctly substituted, satisfying the intended behavior.

Documentation

Overview

Package testroutines holds a collection of common test procedures. They provide a framework to write mock tests.

Index

Constants

View Source
const URLTestServer = "{{testServerURL}}"

URLTestServer is an alias to mock server BaseURL. For usage please refer to ComparatorPagination.

Variables

This section is empty.

Functions

func ComparatorPagination

func ComparatorPagination(serverURL string, actual *common.ReadResult, expected *common.ReadResult) bool

ComparatorPagination will check pagination related fields. Note: you may use an alias for Mock-Server-URL which will be dynamically resolved at runtime. Example:

	common.ReadResult{
		NextPage: testroutines.URLTestServer + "/v3/contacts?cursor=bGltaXQ9MSZuZXh0PTI="
 }

At runtime this may look as follows: http://127.0.0.1:38653/v3/contacts?cursor=bGltaXQ9MSZuZXh0PTI=.

func ComparatorSubsetMetadata

func ComparatorSubsetMetadata(_ string, actual, expected *common.ListObjectMetadataResult) bool

ComparatorSubsetMetadata will check a subset of fields is present.

func ComparatorSubsetRead

func ComparatorSubsetRead(serverURL string, actual, expected *common.ReadResult) bool

ComparatorSubsetRead ensures that a subset of fields or raw data is present in the response. This is convenient for cases where the returned data is large, allowing for a more concise test that still validates the desired behavior.

func ComparatorSubsetWrite

func ComparatorSubsetWrite(_ string, actual, expected *common.WriteResult) bool

ComparatorSubsetWrite ensures that only the specified metadata objects are present, while other values are verified through an exact match..

Types

type Comparator

type Comparator[Output any] func(serverURL string, actual, expected Output) bool

Comparator is an equality function with custom rules. This package provides the most commonly used comparators.

type ConnectorBuilder

type ConnectorBuilder[Conn any] func() (Conn, error)

ConnectorBuilder is a callback method to construct and configure connector for testing. This is a factory method called for every test suite.

func (ConnectorBuilder[C]) Build

func (builder ConnectorBuilder[C]) Build(t *testing.T, testCaseName string) C

type Delete

type Delete DeleteType

Delete is a test suite useful for testing connectors.DeleteConnector interface.

func (Delete) Run

Run provides a procedure to test connectors.DeleteConnector

type Metadata

type Metadata MetadataType

Metadata is a test suite useful for testing connectors.ObjectMetadataConnector interface.

func (Metadata) Run

Run provides a procedure to test connectors.ObjectMetadataConnector

type Read

type Read ReadType

Read is a test suite useful for testing connectors.ReadConnector interface.

func (Read) Run

func (r Read) Run(t *testing.T, builder ConnectorBuilder[connectors.ReadConnector])

Run provides a procedure to test connectors.ReadConnector

type TestCase

type TestCase[Input any, Output any] struct {
	// Name of the test suite.
	Name string
	// Input passed to the tested method.
	Input Input
	// Mock Server which connector will call.
	Server *httptest.Server
	// Custom Comparator of how expected output agrees with actual output.
	Comparator Comparator[Output]
	// Expected return value.
	Expected Output
	// ExpectedErrs is a list of errors that must be present in error output.
	ExpectedErrs []error
}

TestCase describes major components that are used to test any Connector methods. It is universal and generic `Input` data type is what the tested method accepts, while `Output` value represents the data type of the expected output.

func (TestCase[Input, Output]) Validate

func (o TestCase[Input, Output]) Validate(t *testing.T, err error, output Output)

Validate checks if supplied input conforms to the test intention.

type Write

type Write WriteType

Write is a test suite useful for testing connectors.WriteConnector interface.

func (Write) Run

Run provides a procedure to test connectors.WriteConnector

Jump to

Keyboard shortcuts

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