Skip to main content

A dataclasses-inspired approach to test data.

Project description

Plato logo Build and release pipeline Code coverage Latest PyPI version Python versions PyPI - License

Plato

Plato makes it easy to generate complex, but consistent and realistic data for tests with a declarative syntax inspired by dataclasses.

fake = FromFaker()


@formclass
class Address:
    street: str = fake.street_address()
    postal_code: str = fake.postcode()
    city: str = fake.city()
    country: str = "USA"


@formclass
class Customer:
    first_name: str = fake.first_name()
    last_name: str = fake.last_name()
    billing_address: Address = Address()

    @property
    def fullname(self, first_name: str, last_name: str) -> str:
        return f"{first_name} {last_name}"

    @derivedfield
    def email(self, first_name: str, last_name: str) -> str:
        return f"{first_name}.{last_name}@example.com"


pprint(asdict(sample(Customer())))
# Prints:
# {'billing_address': {'city': 'North Reginaburgh',
#                  'country': 'USA',
#                  'postal_code': '03314',
#                  'street': '310 Edwin Shore Suite 986'},
#  'email': 'Denise.Wright@example.com',
#  'first_name': 'Denise',
#  'last_name': 'Wright'}

Vision and Guiding Priniciples

  • Generating consistent and realistic test data should be easy. The more effort it is to produce releastic or consistent test data, the more likely developers take short cuts. This tends to couple tests to the implementation (e.g., because only the fields required for a specific implementation are set, or certain fields are inconsistent with the values of other fields). It also makes it harder to understand, based on the tests, what the expected production data will look like, or can be outright confusing.

  • The code should be declarative. When creating test data one should not be concerned with how it is created, but with what the structure of that data.

  • Try minimize boilerplate to reduce the effort of producing consistent and realistic test data (see above).

  • To be able to easily create complex and varied test data, things should be composable.

  • Test results should be reproducible. Thus, all test data will be generated based on a fixed (but changeable) seed. Plato even tries to keep produced values reproducible when fields are added or deleted from a class.

  • One should have flexibility in how the generated data is used. Therefore, Plato produces dataclasses as output, that can be easily converted into dictionaries and other sorts of objects.

  • No collisions of field names in the test data with Plato’s API. This is achieved similar to dataclasses by not defining Plato’s API as member methods on the formclasses, but as separate functions processing a formclass.

Project Status and Roadmap

The project is currently in a very early stage where I still explore the design space of the API. Thus, breaking changes have to be expected at any time.

The current focus is on finishing the core API together with documentation and examples to test out whether the API would work in real world scenarios.

To get something useful working quickly, Plato currently relies heavily on Faker. In the future, it is intended that Plato also offers certain Providers, but implementing these is not yet the focus.

Here is a very roughly sorted list of additional features and to-dos to consider:

  • Setup CI, static typechecking, linting, auto-formatting

  • Setup website

  • Design a logo

  • Constructor parameters that do not appear as field in the dataclass.

  • Express relations between objects (apart from the composition already possible), especially with respect to relational databases.

  • A standard set of providers

  • Documentation

  • Examples

    • Usage with pytest

    • Usage as builder

    • Usage with ORM

  • A command line interface to generate data (i.e. in JSON format that than can be used for web requests with some other tool)

  • ORM integration

    • With possibility of cleaning up generated data

  • pytest integration

Alternatives

  • Faker is excellent for generating individual pieces of information such as a realistic name, a bank account number, a street address etc. However, it does not provide a convenient way to generate more complex objects.

  • Factory Boy has a very similar aim and scope. As it has been around longer and it is stable, opposed to Plato, you should prefer it for testing production code. However, Plato will have some advantages, such as:

    • Syntax with less boilerplate.

    • It is easier to compose from fields of other sampled objects.

    • API that avoids name collisions, whereas in Factory Boy one has to work around it with renames.

    • By producing data classes conversion into other data formats such as dicts, JSON, etc. is easy and does not require to declare a model class duplicating a lot of information.

    • Reproducible test data even when deleting or adding fields on an object.

Inspirations

Plato was inspired by:

  • Company-internal talks at TNG Technology Consulting GmbH (my employer).

  • Strawberry which gave me the idea to apply the dataclasses approach to other problems.

  • Nengo which gave me the idea to seed random number generator in a way robust against field removal and additions.

  • Factory Boy

Contributing

Contributions are welcome in general.

For bugs, feel free to open issues or pull requests.

If you have an ideas, feedback, or feature requests, also open an issue.

Given the early stage of the project, if you want to implement a feature, I suggest that you open an issue first to discuss the details and ensure that it aligns with the general direction the project is moving into.

Note that it might take me a bit to react as I am working on Plato in my free time besides other projects.

The name

The ancient greek philosopher Plato is well known for his theory of forms. It proposes that, the objects existing in reality are imitations of more pure “Ideas” or “Forms” which are the non-physical essence of things.

In analogy, the library Plato allows you to define the essence or “Form“ of your test data from which the concrete objects used in the tests are derived.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plato-0.2.1.tar.gz (16.5 kB view details)

Uploaded Source

Built Distribution

plato-0.2.1-py3-none-any.whl (15.4 kB view details)

Uploaded Python 3

File details

Details for the file plato-0.2.1.tar.gz.

File metadata

  • Download URL: plato-0.2.1.tar.gz
  • Upload date:
  • Size: 16.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.9.5 Linux/5.4.0-1047-azure

File hashes

Hashes for plato-0.2.1.tar.gz
Algorithm Hash digest
SHA256 ac3d9efe4d8337acca2d02b635dc0f416fdc1807182e03dae4dd075790d4b91d
MD5 a39505eee4aa1f77648760d0cb7e5b5d
BLAKE2b-256 ea90a60cbdb5a8895fe611f2172f47286d602f2ab3cf40ac79746941eff67776

See more details on using hashes here.

File details

Details for the file plato-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: plato-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 15.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.9.5 Linux/5.4.0-1047-azure

File hashes

Hashes for plato-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 dd433e291c53b0da8dc2413c8130f016a75846aa2aafade8a2522956bf836f32
MD5 62ad8e3c22ca8e400f3f5e78358e24d3
BLAKE2b-256 185cdaa6f5827750492c88e9c433226eb83d3db722d4a311cf8f5a5837320713

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page