specimen

module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 2, 2022 License: MPL-2.0

README

Specimen

Yaml-based data-driven testing

Specimen is a yaml data format for data-driven testing. This enforces separation between feature being tested the data used for testing.

It comes with a golang implementation for loading the data, checking its format, running your golang test boxes (called code boxed) and comparing the result with the expected one.

It supports using the FOCUS and PENDING flag in the data to run only part of the test data.

Overview

overview of the way the specimen library works

  • A Codebox is a user-defined named function passed to specimen.run. It serves as an adaptator between Specimen and the user code being tested. It also runs the verification steps after the code being tested has finished.
  • A Slab is a chunk of data to be loaded into a codebox. They are the leaves of the yaml files data tree that Specimen processes.

Getting started

To get started, create a directory it/ and the three files it.go it_test.go and it_testdata.yaml. For each file, copy the content of linked section. Finally, run go test in the it/ directory.

mkdir it
cd it
touch it.go it_test.go it_testdata.yaml

Finally:

go mod init it
go mod tidy
go test

You should get an output like this one:

TestIt:
2 slab-s succeeded over 2. (0 failed)
PASS
ok      it

Yaml Data

The yaml data file looks like this:

content:
  -
    box: turn_page
    content:
      -
        flag: FOCUS
        input:
          book:
            title: aleph
            left_page: 0
            size: 90
          turn_page_count: 4
          expected_result:
            title: aleph
            left_page: 8
            size: 90
      -
        flag: PENDING
        input:
          book:
            title: aleph
            left_page: 0
            size: 90
          turn_page_count: 4
          expected_left_page: 8
  -
    flag: FOCUS
    box: get_page
    input:
      book:
        title: aleph
        left_page: 44
        size: 90
      expected_result: 44

The input entry is required and must be a map. It is passed to the test box. The output entry may be any value but it must only be present if the box returns a value. The supported flags are FOCUS and PENDING - the uppercase is mandatory. This two flags are supported on all nodes of the data tree.

Code box

A code box is an adapter between the parsed data and the library the code being tested. It takes as input the testing context s and the input map. A code box looks like this:

package it_test

import (
    "it"
    "testing"

    "github.com/ditrit/specimen/go/specimen"
)

var codeboxSet = specimen.MakeCodeboxSet(map[string]specimen.BoxFunction{
    "turn_page": func(s *specimen.S, input specimen.Dict) {
        book_data := input["book"].(map[string]interface{})
        book := it.Book{
            Title:    book_data["title"].(string),
            LeftPage: book_data["left_page"].(int),
            Size:     book_data["size"].(int),
        }
        book.TurnPage(input["turn_page_count"].(int))

        s.ExpectEqual(
            specimen.Dict{
                "title":     book.Title,
                "left_page": book.LeftPage,
                "size":      book.Size,
            },
            input["expected_result"].(specimen.Dict),
            "result comparison",
        )
    },
    "get_page": func(s *specimen.S, input specimen.Dict) {
        book_data := input["book"].(map[string]interface{})
        book := it.Book{
            Title:    book_data["title"].(string),
            LeftPage: book_data["left_page"].(int),
            Size:     book_data["size"].(int),
        }
        s.ExpectEqual(
            book.GetPage(),
            input["expected_result"].(int),
            "result comparison",
        )
    },
})

func TestIt(t *testing.T) {
    specimen.Run(
        t,
        codeboxSet,
        []specimen.File{
            specimen.ReadLocalFile("it_testdata.yaml"),
        },
    )
}

Example package code

package it

type Book struct {
    Title    string
    LeftPage int
    Size     int
}

func (b *Book) TurnPage(count int) {
    b.LeftPage += 2 * count

    if b.LeftPage < 0 {
        b.LeftPage = 0
    } else if b.LeftPage >= b.Size {
        b.LeftPage = b.Size - 1
    }
}

func (b *Book) GetPage() int {
    return b.LeftPage
}

Yaml Schema

The content of a yaml test data file must match the main rule of the lidy schema below:

main: nodule

# A nodule which does not contain any child nodule is considered a leaf.
# Slabs must contain an `input` entry even if it is the empty map. They
# must also be associated to a codebox, either locally or through some
# ancestor
nodule:
  _mapFacultative:
    # box is the name of the code box as declared in the code
    box: string
    # content is the children of the current nodule
    content: {_listOf: nodule}
    # input
    input: {_mapOf: {string: any}}
    # name is an indicative name of for the nodule it is mentioned in the error
    # report if present
    name: string
    # if the flag contains FOCUS or PENDING the nodule and its desendents will be
    # prioritized or ignored
    flag: string
    # input contains the entries passed to the box
    input: {_mapOf: {string: any}}
    extra: any

Directories

Path Synopsis
go module
test
zoo

Jump to

Keyboard shortcuts

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