1.3.0 • Published 6 months ago

pict-node v1.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

pict-node

This library is a wrapper around Microsoft's PICT (Pairwise Independent Combinatorial Testing) tool, designed to work with Node.js for generating combinations of inputs for software testing. PICT is a powerful tool that helps reduce the number of tests needed while still ensuring comprehensive coverage by generating optimized combinations of inputs.

The library boasts excellent TypeScript support! 🪄

Before using this library, it's helpful to read Microsoft's official PICT documentation to learn about the tool and how it works.

Installation

npm install --save-dev pict-node

Overview

Imagine you have a function for creating order that accepts 6 parameters with several possible values for each argument.

ParameterPossible Values
LocationUkraine, Poland, Lithuania, Germany, USA
CustomerIndividuals, Companies, Partners
Time05:00, 11:99, 15:00, 21:30, 23:59
Payment SystemVISA, MasterCard, PayPal, WebMoney, Qiwi
Product1732, 319, 872, 650
Discounttrue, false

This model has many possible combinations, which means we could have thousands of test cases to write and test. However, it's not practical to test all of them manually and in a reasonable amount of time. Instead, we can generate and test all possible pairs of values to achieve a good level of coverage.

import { pict } from "pict-node";

const model = [
  {
    key: "location",
    values: ["Ukraine", "Poland", "Lithuania", "Germany", "USA"],
  },
  {
    key: "customer",
    values: ["Individuals", "Companies", "Partners"],
  },
  {
    key: "time",
    values: ["05:00", "11:99", "15:00", "21:30", "23:59"],
  },
  {
    key: "paymentSystem",
    values: ["VISA", "MasterCard", "PayPal", "WebMoney", "Qiwi"],
  },
  {
    key: "product",
    values: [
      {
        id: 1732,
      },
      {
        id: 319,
      },
      {
        id: 872,
      },
      {
        id: 650,
      },
    ],
  },
  {
    key: "discount",
    values: [true, false],
  },
];

const cases = await pict({ model });

PICT will generate the following test cases:

[
  // ... ... ...
  {
    location: "Lithuania",
    customer: "Individuals",
    time: "23:59",
    paymentSystem: "Qiwi",
    product: { id: 650 },
    discount: true,
  },
  {
    location: "USA",
    customer: "Partners",
    time: "05:00",
    paymentSystem: "VISA",
    product: { id: 319 },
    discount: false,
  },
  // ... ... ...
  {
    location: "Ukraine",
    customer: "Companies",
    time: "23:59",
    paymentSystem: "MasterCard",
    product: { id: 1732 },
    discount: true,
  },
  // ... ... ...
];

Generating Test Cases

In most cases, to generate test cases, you can use the pict function. The main features of this function is that you can use any data type for the values of the model.

import { pict } from "pict-node";
import { createOrder } from "./src";

// Define test model
const model = [
  {
    key: "country",
    values: ["Ukraine", "Poland", "USA"],
  },
  {
    key: "age",
    values: [10, 16, 18, 25, 70],
  },
  {
    key: "product",
    values: [{ id: 50 }, { id: 350 }],
  },
];

// Generate test cases
const cases = await pict({ model });

// Iterate test cases
for (const { country, age, product } of cases) {
  // Call a function with the current test case
  const result = createOrder({
    country,
    age,
    product,
  });

  // Verify that the function returns the expected result
  expect(result).toBe("The order has been created");
}

By default, pict-node generates a pair-wise test suite (all pairs covered), but the order can be set by option order to a value larger than two.

const cases = await pict(
  {
    model,
  },
  {
    order: 3,
  }
);

TypeScript 🪄

Here is an example of using this tool with TypeScript:

import { pict, alias, weight } from "pict-node";

const model = [
  {
    key: "amount",
    //                           ↓↓↓↓↓↓↓↓
    values: [1, alias([2, "two"] as const), 3],
  },
  {
    key: "fruit",
    //                       ↓↓↓↓↓↓↓↓
    values: [weight("Banana" as const, 10), "Orange", "Apple"],
  },
  // ↓↓↓↓↓
] as const;

const cases = await pict({ model });

The type of cases will be:

Array<{
  amount: 1 | 2 | "two" | 3;
  fruit: "Banana" | "Orange" | "Apple";
}>;

⚠️ Note that we use as const to get a literal types!

Without as const the type of cases will be:

Array<{
  amount: number | string;
  fruit: string;
}>;

Constraints

Read PICT documentation to get more information about constraints.

Constraints are only applicable when using the strings function, which only accepts string values and provides additional options:

  • aliasSeparator - the separator used for aliases (default: |)
  • valueSeparator - the separator used for values (default: ,)
  • negativePrefix - the prefix used for negative values (default: ~)
  • caseSensitive - case sensitive (default: false)

⚠️ Be aware that the characters used for aliasSeparator, valueSeparator, and negativePrefix cannot be used in your values. If you must use them, you must replace them using the second argument (options).

import { strings } from "pict-node";

const model = [
  {
    key: "type",
    values: ["Primary", "Logical", "Single"],
  },
  {
    key: "size",
    values: ["10", "100", "500", "1000", "5000", "10000", "40000"],
  },
  {
    key: "fileSystem",
    values: ["FAT", "FAT32", "NTFS"],
  },
];

const constraints = [
  'IF [fileSystem] = "FAT"   THEN [Size] <= 4096;',
  'IF [fileSystem] = "FAT32" THEN [Size] <= 32000;',
];

const cases = await strings(
  {
    model,
    constraints,
  },
  {
    caseSensitive: true,
  }
);

If you need to use values of different types, you can use the pict function instead of the strings function. This way, you can specify any type you want for the values of your model.

Sub-Models

Read PICT documentation to get more information about sub-models.

Sub-models can be used with both the pict and strings API functions, and they are defined using the sub property.

import { pict } from "pict-node";

const model = [
  {
    key: "platform",
    values: ["x86", "x64", "arm"],
  },
  {
    key: "ram",
    values: [1, 4, 64],
  },
  {
    key: "os",
    values: ["Win7", "Win8", "Win10"],
  },
  {
    key: "browser",
    values: ["Edge", "Opera", "Chrome", "Firefox"],
  },
];

const sub = [
  {
    keys: ["os", "browser"],
    order: 2, // optional
  },
];

const cases = await pict({
  model,
  sub,
});

Seeding

Read PICT documentation to get more information about seeding.

Seeding can be used with both the pict and strings API functions, and they are defined using the seed property.

import { pict } from "pict-node";

const model = [
  {
    key: "platform",
    values: ["x86", "x64", "arm"],
  },
  {
    key: "ram",
    values: [1, 4, 64],
  },
  {
    key: "os",
    values: ["Win7", "Win8", "Win10"],
  },
  {
    key: "browser",
    values: ["Edge", "Opera", "Chrome", "Firefox"],
  },
];

const seed = {
  ram: [64],
  browser: ["Opera", "Firefox"],
};

const cases = await pict({
  model,
  seed,
});

Aliasing

Read PICT documentation to get more information about aliasing.

There is a special function alias that can be used to create aliases for values. It can be used with both the pict and strings API functions.

import { pict, alias } from "pict-node";

const model = [
  {
    key: "os",
    values: ["Win7", "Win8", alias(["Win10", "Windows10"])],
  },
  {
    key: "platform",
    values: ["x86", "x64", "arm"],
  },
  {
    key: "ram",
    values: [1, 4, 64],
  },
];

const cases = await pict({ model });

Negative Testing

Read PICT documentation to get more information about negative testing.

There is a special function negative that can be used to create a value for negative testing. It can be used with both the pict and strings API functions.

import { pict, negative } from "pict-node";

const model = [
  {
    key: "A",
    values: [negative(-1), 0, 1, 2],
  },
  {
    key: "B",
    values: [negative(-1), 0, 1, 2],
  },
];

const cases = await pict({ model });

Weighting

Read PICT documentation to get more information about weighting.

There is a special function weight that can be used to create a value with weight. It can be used with both the pict and strings API functions.

import { pict, weight } from "pict-node";

const model = [
  {
    key: "type",
    values: [weight("Primary", 5), "Logical", "Single", "Span"],
  },
  {
    key: "formatMethod",
    values: ["quick", "slow"],
  },
  {
    key: "fileSystem",
    values: ["FAT", "FAT32", weight("NTFS", 10)],
  },
];

const cases = await pict({ model });

Randomization

Read PICT documentation to get more information about randomization.

If the model does not change, running it repeatedly will result in the same output. To introduce randomness, you can use the random option.

It applies to pict, strings and native API.

import { pict, negative } from "pict-node";

const model = [
  // ...
];

const cases = await pict(
  { model },
  {
    random: true,
    // random: 19285 - or using with seed
  }
);

Native PICT Models

You can use native PICT models with native API function.

native accepts the following options (optional):

  • order - order of combinations (default: 2)
  • random - randomization
  • aliasSeparator - the separator used for aliases (default: |)
  • valueSeparator - the separator used for values (default: ,)
  • negativePrefix - the prefix used for negative values (default: ~)
  • caseSensitive - case sensitive (default: false)

A model can be a file:

import { native } from "pict-node";

const cases = await native({
  model: {
    file: "path/to/file",
    seed: "path/to/seed/file", // optional,
    options: {
      caseSensitive: true,
    },
  },
});

A model and a seed can be a string:

import { native } from "pict-node";

const cases = native({
  model: `
  PLATFORM:  x86, x64, arm
  RAM:       1GB, 4GB, 64GB
  OS:        Win7, Win8, Win10
  Browser:   Edge, Opera, Chrome, Firefox
  `,
});

Statistics

You can obtain model statistics using the stats method.

This method is accessible through the pict, strings, and native APIs.

import { pict } from "pict-node";

const model = [
  {
    key: "platform",
    values: ["x86", "x64", "arm"],
  },
  {
    key: "ram",
    values: [1, 4, 64],
  },
];

const stats = await pict.stats({
  model,
});

The stats method returns an object with the following fields:

  • generationTimeNodeJs - model generation time (including Node.js processing time)
  • generationTime - model generation time (excluding Node.js processing time)
  • combinations - number of combinations
  • generatedTests - number of generated tests

License

MIT

1.3.0

6 months ago

1.2.0

11 months ago

1.2.1

9 months ago

1.1.1

1 year ago

1.1.0

1 year ago

1.0.0

1 year ago