Cuerdo. ArazzoCase
(cuerdo v0.4.0)
Copy Markdown
Provides an ExUnit.CaseTemplate for automatically generating tests from Arazzo workflows.
Each workflow in the document is executed as a test, with automatically generated inputs derived from the workflow's input schema.
Basic Usage
Define use Cuerdo.ArazzoCase in your test module, and add arazzo_document_test macro
referencing the document you want to test
defmodule MyArazzoTest do
use Cuerdo.ArazzoCase
arazzo_document_test document: YamlElixir.read_from_file!("spec/to/arazzo.yaml")
endFiltering workflows
You can opt-in and opt-out from executing specific workflows via the :only and :exclude
options respectively. For example:
# Executes "workflow1" and "workflow2"
arazzo_document_test only: ["workflow1", "workflow2"], document: ...
# Executes every workflow defined in the document except for "workflow1"
arazzo_document_test exclude: ["workflow1"], document: ...
# Executes "workflow1"
arazzo_document_test only: ["workflow1", "workflow2"], exclude: ["workflow2"], document: ...Customizing Generated Inputs
Consider for example a "book" input containing the book's title, author and ISBN:
{
"type": "object",
"additionalProperties": false,
"properties": {
"title": {"type": "string", "minLength": 1},
"authorName": {"type": "string", "minLength": 1},
"isbn": {"type": "string", "pattern": "^97(8|9)[0-9]{10}$"}
}
}Valid ISBNs cannot be generated from JSON schemas. Values might match the regular expression
while failing the checksum validation. We can work around this issue via
the :transform_inputs option.
Define a function that generates valid ISBN identifiers:
defmodule MyModule do
def valid_isbn do
StreamData.bind(MoreStreamData.from_regex("^97(8|9)[0-9]{10}$"), fn invalid_isbn ->
{digits, _wrong_check_digit} = String.split_at(invalid_isbn, 12)
StreamData.constant(digits <> to_string(check_digit(digits)))
end)
end
defp check_digit(digits) do
digits
|> String.codepoints()
|> Enum.with_index()
|> Enum.sum_by(fn {digit, idx} ->
digit = String.to_integer(digit)
if(rem(idx, 2) == 0, do: digit, else: 3 * digit)
end)
|> then(fn total -> 10 - rem(total, 10) end)
endDefine a transformation function that replaces the generated ISBN with a valid one. Notice
that the function must return a StreamData.t/1 generator:
def with_valid_isbn(book) do
StreamData.bind(valid_isbn(), fn isbn ->
StreamData.constant(Map.put(book, "isbn", isbn))
end)
endPass the transformation function through :transform_inputs option, as an MFA tuple.
The function will be called for every input generated for the specified workflow, before
starting to execute the first workflow step:
defmodule MyModuleTest do
use Cuerdo.ArazzoCase
arazzo_document_test transform_inputs: %{
"createBookWorkflow" => {MyModule, :with_valid_isbn, []}
},
document: ...
endRunning the same document multiple times
Declaring multiple arazzo_document_test allows for different execution strategies for
the same document, such as:
- Running expensive/slower workflows fewer times
- Running workflows with different input transformations
defmodule MyArazzoTest do
use Cuerdo.ArazzoCase
arazzo_document_test transform_inputs: %{"workflowId" => {Module, :function, []}},
document: YamlElixir.read_from_file!("path/to/arazzo.yaml")
arazzo_document_test document: YamlElixir.read_from_file!("path/to/arazzo.yaml")
endKeep in mind that the test names are generated based on each workflow's workflowId field. If
the Arazzo documents contains workflows with the same name then you must pass the :prefix
option, otherwise the test generation will fail:
defmodule MyArazzoTest do
use Cuerdo.ArazzoCase
arazzo_document_test prefix: "custom_inputs",
transform_inputs: %{"workflowId" => {Module, :function, []}},
document: YamlElixir.read_from_file!("path/to/arazzo.yaml")
arazzo_document_test prefix: "default_inputs",
document: YamlElixir.read_from_file!("path/to/arazzo.yaml")
end
Summary
Functions
Generates property tests for every workflow in the Arazzo document.
Functions
Generates property tests for every workflow in the Arazzo document.
Options
:document(map/0) - Arazzo document:only(list(String.t())) - List ofworkflowIdto execute from the document. If provided, workflows that are not in the:onlyoption are not tested. Defaults to executing all workflows in the document:exclude(list(String.t())) - List ofworkflowIdto exclude from the document. If both:onlyand:excludeare passed then the workflows from:onlythat are not in:excludedare executed:max_runs(pos_integer/0) - The number of cases to run. Defaults to1:max_shrink_steps(pos_integer/0) - Maximum number of shrinking steps to apply. Defaults to0:transform_inputs- A map of%{workflowId => transformation}, wheretransformationis a function that generatesStreamData.t/1based on the initially generated value, specified as{Module, :function_name}, where:function_nameis a 1-arity function:json_schema_resolver- The resolver to use for fetching JSON Schemas. Defaults to a do-nothing resolver. Use this option if any OpenAPI document in your workflow references remote schemas. Refer to JSV Resolvers section for more information:prefix- (String.t/0) - The test name prefix