Examples of test assertions

Practical examples of test assertions

This page lists examples of how to specify common test assertions to cover message structure and content requirements. Before diving into details, we recommend to get familiar with the basics of test assertions.

Around 80-90% of requirements can be usually specified using our no-code/low-code interface (Truugo Subset Editor). The rest can be implemented as test assertions using Assertion Editor.

Test assertions for XML

Cardinality

A credit note must contain a non-empty reference to an initial invoice.

Target
/CreditNote the requirement applies to the whole message => use root node as a target
Predicate
InvoiceReferenceID[normalize-space()] must exists non-empty invoice reference
Error notice
'Missing a non-empty element InvoiceReferenceID' error notice as a static text

Each invoice line must contain an item number.

Target
/ZORDERS5/IDOC/E1EDP01 the requirement applies to all invoice lines (E1EDP01)
Predicate
E1EDP19[QUALF="001"] use filter [...] to specify which E1EDP19 must exist
Error notice
'E1EDP01 is missing E1EDP19[QUALF="001"]' error notice as a static text

Each monetary amount must include a non-empty currency code.

Target
//Amount the requirement applies to all monetary amounts
Predicate
@currencyID[normalize-space()] must exist non-empty attribute @currencyID for each monetary amount
Error notice
'Missing a non-empty attribute @currencyID' error notice as a static text

The credit note must contain a reference to one and only one invoice document.

Target
/CreditNote the requirement applies to the whole message
Predicate
count(BillingReference/InvoiceDocumentReference)=1 must exist exactly one InvoiceDocumentReference
Error notice
concat('Found ', count(BillingReference/InvoiceDocumentReference), ' invoice references') use concat function to combine static and dynamic text

Postal code must be stated when an address includes a street name.

Target
//Address the requirement applies to all addresses
Precondition
StreetName[normalize-space()] apply predicate test when non-empty StreetName exists
Predicate
PostalCode[normalize-space()] must exist non-empty PostalCode
Error notice
concat('Address with a street "', StreetName, '" is missing a postal code.') use concat function to combine static and dynamic text

Either name or id must be specified for each party role.

Target
//Party the requirement applies to all parties
Predicate
Name[normalize-space()] or ID[normalize-space()] must exist non-empty Name or ID
Error notice
'Party missing both name and id' error notice as a static text

Format and enumeration

An element employment_type must contain one of the values: 01, 02, 03, 05

Target
/job_announcement/place_of_work/employment_type the requirement applies to the element "employment_type"
Predicate
appFunction('validPattern', text(), '01|02|03|05') use validPattern function from Truugo function library
Error notice
concat('Invalid value: "', text(), '"') use concat function to combine dynamic and static text

Bank account's identification scheme must be either BBAN or IBAN.

Target
//SellerAccountID[@schemaID] the requirement applies to @schemeID but you cannot use attributes as target nodes
Predicate (option 1)
@schemeID="BBAN" or @schemeID="IBAN" list valid values in a simple way
Predicate (option 2)
appFunction('validPattern', @schemeID, 'BBAN|IBAN') use validPattern function from Truugo function library when there is a long list of valid values
Error notice
concat('Invalid value: "', text(), '"') use concat() function to combine dynamic and static text

Seller's and buyer's bank accounts are identified using the IBAN number.

Target
//SellerAccountID|//BuyerAccountID the requirement applies to seller's and buyer's account
Predicate
appFunction('validIBAN', text()) use validIBAN function from Truugo function library
Error notice
concat('Invalid value: ', text()) use concat function to combine static and dynamic text

Country must be identified using ISO 2-letter country code.

Target
//CountryCode the requirement applies to all country code elements
Predicate
appFunction('validCountryCode', text()) use validCountryCode function from Truugo function library
Error notice
concat('Invalid value: ', text()) use concat function to combine static and dynamic text

Text content must not contain URLs/links.

Target
//description|//contact_details the requirement applies to description and contact_details elements (use pipe sign set multiple targets)
Local variables
$pattern = '.*https?:\/\/.*'
check if http(s):// is included to the text $caseSensitive = false
the requirement applies to both lowercase and uppercase text
Precondition
normalize-space() apply predicate test to non-empty elements only
Predicate
not(appFunction('validPattern', text(), $pattern, $caseSensitive)) use validPattern function from Truugo function library
Error notice
concat('Links found from: ', text()) use concat function to combine static and dynamic text

Integrity

The invoice due date must be later than the invoice issue date.

Target
/Invoice/InvoiceDueDate the requirement applies to the invoice due date
Precondition
normalize-space() apply check only if the due date is non-empty
Predicate
translate(text(), '-', '') > translate(/Invoice/IssueDate, '-', '') compare date values (yyyy-mm-dd) by translating them into integer values
Error notice
concat('InvoiceDueDate ' = "', text(), '" (IssueDate = "', /Invoice/IssueDate, '")') use concat function to combine static and dynamic text

Target
/Invoice/InvoiceLine[not(VatPercent=preceding-sibling::InvoiceLine/VatPercent)]/VatPercent the requirement applies to all distinct VAT percent values (using preceding-sibling for filtering)
Local variables
$vatPercent = string() read VAT percent to variable to use it as a filter in the predicate test
Predicate
/Invoice/TaxTotal/TaxSubtotal[VatPercent=$vatPercent] must exists a tax subtotal for the given VAT percent
Error notice
concat('Missing TaxTotal/TaxSubtotal for the VAT percent "', text(), '"') use concat function to combine static and dynamic text

Tax amount must match the value of the taxable amount multiplied with the tax percent.

Target
/Invoice/TaxTotal/TaxSubtotal/TaxAmount the requirement applies to TaxAmount
Local variables
$taxableAmount = ../TaxableAmount
$taxPercent = ../TaxCategory/Percent
$calculatedTaxAmount = $taxableAmount * ($taxPercent div 100)
$statedTaxAmount = text()
Predicate
appFunction('countDiff', $statedTaxAmount, $calculatedTaxAmount, 2) <= 0.01 use countDiff function from Truugo function library to check the gap (max 0.01)
Error notice
concat('The stated tax amount ', $statedTaxAmount, ' does not match with the calculated amount ', appFunction('formatNumber', $calculatedTaxAmount, 2), ').') use concat function to combine static and dynamic text

Test assertions for EDIFACT

Cardinality

Each despatched item (GRP17) must contain quantity details (QTY).

Target
/DESADV/GRP10/GRP17 the requirement applies to the segment group 17
Predicate
QTY each target node must contain QTY segment
Error notice
'Missing QTY segment' error notice as a static text

The invoice must contain a payment reference (RFF+PQ).

Target
/INVOIC the requirement applies to a whole message => use message root node as the target
Predicate
GRP1/RFF/C506[e1153="PQ"] must exists RFF segment with the qualifier "PQ"
Error notice
'Payment reference (RFF="PQ") is missing.' error notice as a static text

UNH segment must contain a non-empty element 0057 (association assigned code).

Target
/INVOIC/UNH/S009 the requirement applies to UNH.S009
Predicate
e0057[normalize-space()] must exist a non-empty element 0057
Error notice
'Missing a non-empty element 0057.' error notice as a static text

Order reference (RFF+CO) on an invoice line must contain a line number (1156).

Target
/INVOIC/GRP21/GRP25/RFF/C506[e1153="CO"] the requirement applies to RFF+CO segments on a line level (GRP21)
Predicate
e1156[normalize-space()] must exists non-empty element 1156
Error notice
'RFF+CO missing a non-empty line number 1156.' error notice as a static text

The credit note must contain a reference to one and only one invoice document.

Target
/* the requirement applies to the whole message
Predicate
count(GRP1/RFF[C506/e1153="IV"])=1 must exist exactly one invoice reference RFF+IV
Error notice
concat('Found ', count(GRP1/RFF[C506/e1153="IV"]), ' invoice references') use concat function to combine static and dynamic text

The measurement details (MEA) must be provided either as an exact value (e6314) or as a range with both minimum and maximum value (e6162 and e6152).

Target
/DESADV/MEA/C174 the requirement applies to MEA.C174
Precondition
not(e6162) or not(e6152) apply the predicate test if the range (min + max) is not provided
Predicate
e6314 must exist element 6314
Error notice
'Missing an exact value (6314) or a range (6162+6152).' error notice as a static text

Format and enumeration

The invoice message type must be either a commercial invoice (380) or a credit note (381).

Target
/INVOIC/BGM/C002/e1001 the requirement applies to the element UNH.C002.1001
Predicate (option 1)
text()="380" or text()="381" list valid values in a simple way
Predicate (option 2)
appFunction('validPattern', text(), '380|381') use validPattern function from Truugo function library when there is a long list of valid values
Error notice
concat('Invalid value "', text(), '"') use concat function to combine dynamic and static strings

Date values (DTM.C507.2380) must be specified using the format CCYYMMDD when 2379=102.

Target
//DTM/C507[e2379=102]/e2380 the requirement applies to all DTM date values having the format code "102"
Precondition
normalize-space() apply the predicate test to non-empty date values only
Predicate
appFunction('validDate', text(), 'YYYYMMDD') use validDate function from Truugo function library
Error notice
concat('Invalid value "', text(), '"') use concat function to combine dynamic and static strings

Integrity

The tax-inclusive total amount (MOA+39) must match the value calculated from the line-level values MOA+79 (total line items amount, tax exclusive) and TAX++VAT (Value added tax).

Target
/INVOIC/GRP44/MOA/C516[e5025="39"]/e5004 the requirement applies to the element 5004 of the MOA+39 segment
Local variables
$lineTaxExclusiveAmounts = /*/GRP21/GRP22/MOA/C516[e5025="79"]/e5004
$lineTaxPercents = /*/GRP21/GRP29/TAX[C241/e5153="VAT"]/C243/e5278
$lineTaxTotal = appFunction('countSumProduct', $lineTaxPercents, $lineTaxExclusiveAmounts) div 100
use countSumProduct function from Truugo function library to calculate the total tax amount $lineTaxExclusiveTotal = sum($lineTaxExclusiveAmounts)
use XPath function sum() to calculate the total tax exclusive amount $lineTaxInclusiveTotal = $lineTaxExclusiveTotal+$lineTaxTotal
Predicate
appFunction('countDiff', $lineTaxInclusiveTotal, text()) < 1 the difference of the stated and calculated tax sums must be less than 1 (euro)
Error notice
concat('Value "', text(), '" does not match with the calculated line sum "', $lineTaxInclusiveTotal, '".') use concat function and local variables to combine static and dynamic text

The packaging level must be specified in the following way: The parent level must be stated before its children and the parent level must have a higher packaging level (CPS.7075) than its children have.

Target
/DESADV/GRP10/CPS the requirement applies to all CPS segments
Local variables
$e7166 = string(e7166)
target node's hierarchical parent id stored to $7166 variable to use it as a filter for locating the parent level $parent_CPS = ../preceding-sibling::GRP10/CPS[e7164=$e7166] parent must be specified before its children => parent CPS must be found using the preceding-sibling axis
Predicate
$parent_CPS and $parent_CPS/e7075 > e7075 parent must exists and it must have a higher packaging level code (7075) than its child
Error notice
concat('CPS has the hierarchy level "', e7075, '". Its parent CPS was not found or it does not have a higher packaging level code.') use concat function and local variables to combine static and dynamic text

The consolidation item number (receptacle serial number) must be identical to the characters 21–23 of the document identifier (receptacle-ID).

Target
/IFCSUM/GRP26/CNI the requirement applies to CNI segment
Predicate
string(e1490)=substring(C503/e1004, 21, 3) the value of the element 1490 must match with characters 21–23 of the receptacle-ID
Error notice
concat('Consolidation item number "', e1490, '" does not match with the chars 21-23 "', C503/e1004, '" of the receptacle-id.') use concat function and local variables to combine static and dynamic text

Examples for use of advanced options

The credit note must contain a reference to a commercial invoice.

Namespaces
doc = urn:oasis:names:specification:ubl:schema:xsd:Invoice-2
cac = urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2
cbc = urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2
specify namespaces prefixes to be used instead of URIs (defined once per test profile)
Target
/doc:CreditNote the requirement applies to a whole message (using namespace prefix instead of the long URI)
Predicate
cac:BillingReference/cac:InvoiceDocumentReference/cbc:ID[normalize-space()] must contain a non-empty ID reference
Error notice
'Missing non-empty cac:InvoiceDocumentReference/cbc:ID' error notice as a static text

The ordered item must be from the product catalog.

Global variable
$enumItemID = document('ProductCatalog.xml')//Item/ID read all item ids from the product catalog (separate XML file) to a global variable
Target
//Item/ID the requirement applies to all item identifiers stated within an order message
Predicate
$enumItemID = text() the item ID must be one of the listed values
Error notice
concat(appFunction('getPath', self::node()), ' = ', text()) use concat function and 'getPath' function to display both the invalid value and the path of the invalid element

Each order line must contain item ID except in work orders.

Global variable
$strictValidation = appFunction('IfThenElse', /Order/ProfileID="WORK", false(), true()); use a global variable to specify cases where the strict validation must be applied strict/loose "switch" can also be used to separate for example development/production rule sets
Target
//OrderLine the requirement applies to all order lines
Precondition
$strictValidation=true() apply predicate check only if strict validation is enabled
Predicate
Item/ID[normalize-space()] order line must contain a non-empty item ID
Error notice
'Missing a non-empty Item/ID'

The invoice total amount must match with a sum of line amounts.

Target
/Invoice/InvoiceTotalAmount the requirement applies to InvoiceTotalAmount
Local variable
$sumLineAmount = appFunction('countSum', //InvoiceLine/LineAmount, 2) use countSum function from Truugo function library to calculate the sum of line amount rounded to two decimals digits
Predicate
appFunction('countDiff', text(), $sumLineAmount) <= 0.01 use coutDiff function from Truugo function library to check that the gap between the stated and calculated total amount (max 0.01)
Error notice
concat('InvoiceTotalAmount = ', text(), '(calculated amount: ', $sumLineAmount, ')') use concat and variables to combine static and dynamic text

Need further examples? Send us a suggestion of an assertion type you wish to see!