Documentation ¶
Overview ¶
Package specs
Summary ¶
This package implements generic CRUD operation related testing specifications that commonly appears upon interacting with external resources.
Reason for separate pkg from resources pkg ¶
This package originally was part of the resources pkg, but package "testing" has side effects on import. In order to avoid force the import on the implementations, the specs had to be extracted into a separate package. Since testing#T.Run is heavily used, abstracting testing.T away is difficult.
Minimum Requirement from Resource point of view ¶
In order to make this package work, you have to implement the TestMinimumRequirementsWithExampleEntities specification. Most of the other Resource specs specification depends on the Resource specs mentioned in the min requirement specification. Keep in mind, that you have no guarantee on your Resource content during test execution, because some specification may alter the content of the Resource (db), or delete from it. If you need specific data in the Resource you want to test with, you must ensure in the test execution that such Context is correctly provisioned, and after test execution, cleaned up. If you use such data-set in a external Resource that needs to be kept intact, I advise you to use separate environments for test execution and manual testing.
Requirement from Business Entities ¶
This package depends on a fact that there is a string field ID in a business entity struct, or at least a tag `ext:"ID"`. This allows the package to create specifications that assumes, that the ID field links the EntityTypeName structure to an external Resource object. The Resource specs package doesn't care about the content of the ID string field, and don't have assumptions other than the existence of the field ID on a struct
Index ¶
- Constants
- Variables
- func CreateEntity(tb testing.TB, subject CRD, ctx context.Context, ptr interface{})
- func DeleteAllEntity(tb testing.TB, subject CRD, ctx context.Context, T frameless.T)
- func DeleteEntity(tb testing.TB, subject CRD, ctx context.Context, ent interface{})
- func HasEntity(tb testing.TB, subject frameless.Finder, ctx context.Context, ent interface{})
- func HasID(tb testing.TB, ent interface{}) (id interface{})
- func IsAbsent(tb testing.TB, T T, subject frameless.Finder, ctx context.Context, ...)
- func IsFindable(tb testing.TB, T T, subject frameless.Finder, ctx context.Context, ...) interface{}
- func UpdateEntity(tb testing.TB, subject interface{ ... }, ctx context.Context, ptr interface{})
- type CRD
- type Creator
- type CreatorPublisher
- type CreatorPublisherSubject
- type Deleter
- type DeleterPublisher
- type DeleterPublisherSubject
- type FindOne
- type Finder
- type FixtureFactory
- type FixtureFactorySpec
- type Interface
- type OnePhaseCommitProtocol
- type QueryOne
- type T
- type Updater
- type UpdaterPublisher
- type UpdaterPublisherSubject
- type UpdaterSubject
Constants ¶
const ErrIDRequired frameless.Error = `` /* 174-byte string literal not displayed */
Variables ¶
var AsyncTester = testcase.Retry{Strategy: Waiter}
var Waiter = testcase.Waiter{ WaitDuration: time.Millisecond, WaitTimeout: 5 * time.Second, }
Functions ¶
func CreateEntity ¶
func DeleteAllEntity ¶
func DeleteEntity ¶
func IsFindable ¶
Types ¶
type CreatorPublisher ¶
type CreatorPublisher struct { T Subject func(testing.TB) CreatorPublisherSubject FixtureFactory FixtureFactory }
func (CreatorPublisher) Benchmark ¶
func (spec CreatorPublisher) Benchmark(b *testing.B)
func (CreatorPublisher) Spec ¶
func (spec CreatorPublisher) Spec(tb testing.TB)
func (CreatorPublisher) Test ¶
func (spec CreatorPublisher) Test(t *testing.T)
type CreatorPublisherSubject ¶
type CreatorPublisherSubject interface { CRD frameless.CreatorPublisher }
type DeleterPublisher ¶
type DeleterPublisher struct { T Subject func(testing.TB) DeleterPublisherSubject FixtureFactory FixtureFactory }
func (DeleterPublisher) Benchmark ¶
func (spec DeleterPublisher) Benchmark(b *testing.B)
func (DeleterPublisher) Test ¶
func (spec DeleterPublisher) Test(t *testing.T)
type DeleterPublisherSubject ¶
type DeleterPublisherSubject interface { CRD frameless.DeleterPublisher }
type FindOne ¶
type FindOne struct { T Subject func(testing.TB) CRD FixtureFactory // MethodName is the name of the test subject QueryOne method of this contract specification. MethodName string // ToQuery takes an entity ptr and returns with a closure that has the knowledge about how to query on the Subject resource to find the entity. // // By convention, any preparation action that affect the Storage must take place prior to returning the closure. // The QueryOne closure should only have the Method call with the already mapped values. // ToQuery will be evaluated in the beginning of the testing, // and executed after all the test Context preparation is done. ToQuery func(tb testing.TB, resource interface{}, ent T) QueryOne // Specify allow further specification describing for a given FindOne query function. // If none specified, this field will be ignored Specify func(testing.TB) }
type FixtureFactory ¶
type FixtureFactory interface { // Create create a newEntity struct instance based on the received input struct type. // Create also populate the struct field with dummy values. // It is expected that the newly created fixture will have no content for extID field. //Create(testing.TB, context.Context, any) any Create(T interface{}) (ptr interface{}) // Context able to provide the specs with a Context object for a certain entity Type. Context() (ctx context.Context) }
type FixtureFactorySpec ¶
type FixtureFactorySpec struct { Type interface{} FixtureFactory }
func (FixtureFactorySpec) Benchmark ¶
func (spec FixtureFactorySpec) Benchmark(b *testing.B)
func (FixtureFactorySpec) Test ¶
func (spec FixtureFactorySpec) Test(t *testing.T)
type Interface ¶
Interface represent a resource specification also known as "contract".
The main goal of a resource Spec is to introduce dependency injection pattern at logical level between consumers and suppliers. In other words any expectations from a consumer/interactor/use-case towards a used dependency should be defined in a contract. This allows architecture flexibility since the expectations not bound to a certain technology, but purely high level and as such can be implemented in various ways.
Using resource Spec also force the writer of the Spec to keep things at high level and only focus on the expected behavior, instead of going into implementation details.
type OnePhaseCommitProtocol ¶
type OnePhaseCommitProtocol struct { T Subject func(testing.TB) (frameless.OnePhaseCommitProtocol, CRD) FixtureFactory FixtureFactory }
func (OnePhaseCommitProtocol) Benchmark ¶
func (spec OnePhaseCommitProtocol) Benchmark(b *testing.B)
func (OnePhaseCommitProtocol) Context ¶
func (spec OnePhaseCommitProtocol) Context() context.Context
func (OnePhaseCommitProtocol) Spec ¶
func (spec OnePhaseCommitProtocol) Spec(tb testing.TB)
func (OnePhaseCommitProtocol) Test ¶
func (spec OnePhaseCommitProtocol) Test(t *testing.T)
type QueryOne ¶
QueryOne is the generic representation of a query that meant to find one result. It is really similar to resources.Finder#FindByID, with the exception that the closure meant to know the query method name on the subject and the inputs it requires.
QueryOne is generated through ToQuery factory function in FindOne resource contract specification.
type Updater ¶
type Updater struct { T Subject func(testing.TB) UpdaterSubject FixtureFactory }
Updater will request an update for a wrapped entity object in the Resource
type UpdaterPublisher ¶
type UpdaterPublisher struct { T Subject func(testing.TB) UpdaterPublisherSubject FixtureFactory }
func (UpdaterPublisher) Benchmark ¶
func (spec UpdaterPublisher) Benchmark(b *testing.B)
func (UpdaterPublisher) Spec ¶
func (spec UpdaterPublisher) Spec(tb testing.TB)
func (UpdaterPublisher) Test ¶
func (spec UpdaterPublisher) Test(t *testing.T)
type UpdaterPublisherSubject ¶
type UpdaterPublisherSubject interface { CRD frameless.Updater frameless.UpdaterPublisher }