Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mountebank extensions #14

Closed
moodmosaic opened this issue May 10, 2014 · 4 comments
Closed

mountebank extensions #14

moodmosaic opened this issue May 10, 2014 · 4 comments

Comments

@moodmosaic
Copy link
Contributor

tl;dr
A hypothetical extension for mountebank could supply over the wire Equivalence Sets for primary data types (String, Number, Boolean) and composite data types (Object, Array).

Motivation

Test Doubles (Mocks, Spies, Stubs, etc) often play an important role in test robustness – another concept in test robustness is the Equivalence Classes (or Equivalence Sets).

Pareto principle

Imagine, for example, a SUT that accepts a direct input value and if the input value is > 1 and < 100 the expected value is always equal to actual result value.

In this example, any number from the Equivalence Set [1 .. 100] is guaranteed to exercise the same path of the code thus making the test more robust.

In AutoFixture we have generalized this approach by the 80–20 rule:

In most mainstream scenarios, numbers of the Equivalence Set [1 .. 255] tend to exercise the same path in the code.

In practise

The same way we create an imposter – we could ask a mountebank extension to create a fixture and transmit values for requested data types drained from an Equivalence Set over the wire.

A good collection of Equivalence Sets for primary data types (String, Number, Boolean) gives the ability to create composite data types (Object, Array).

Example

One could request the following JSON Schema from a mountebank extension:

{
    "name": "Product",
    "properties": {
        "id": {
            "type": "number",
            "description": "Product identifier",
            "required": true
        },
        "name": {
            "type": "string",
            "description": "Name of the product",
            "required": true
        },
        "price": {
            "type": "number",
            "minimum": 0,
            "required": true
        },
       "datetime": {
            "type": "date"
        },
        "tags": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "stock": {
            "type": "object",
            "properties": {
                "warehouse": {
                    "type": "number"
                },
                "retail": {
                    "type": "number"
                }
            }
        }
    }
}

And the mountebank extension would respond with a JSON generalized by the 80–20 rule:

{
    "id": 50,
    "name": "89071263-eeb2-4a1d-84bf-31c760360bc9",
    "price": 123,
    "datetime": "2014-05-10T00:18:40.055Z" 
    "tags": [ "Bar-89071263-eeb2", "Eek-89071263-eeb2" ],
    "stock": {
        "warehouse": 300,
        "retail": 20
    }
}

It should be also possible to create custom Equivalence Sets (via HTTP) by specifying the Boundary Values in the JSON string.

Benefits

Mountebank could eventually become the de facto, truly cross-platform, tool around test robustness, capable of creating Test Doubles, and also Fixtures via extensions using Equivalence Sets generalized by the 80–20 rule.

References


If this hypothetical mountebank extension falls into a direction you would like to take, please let me know. I may work on it, in my spare time, and I may open a pull request sometime.

@bbyars
Copy link
Owner

bbyars commented May 10, 2014

I definitely like the idea. I think it's worth playing with how to represent this in the RESTful API. I didn't completely follow how the schema gets to mountebank in your example above, but given the AutoFixture-like response (AutoFixture is great, btw), it somehow needs to know how to generate the response. One idea could be as a different behavior with the schema inside the behavior definition:

{
    "port": 4545,
    "protocol": "http",
    "stubs": [
        {
            "responses": [
                {
                    "is": {
                        "statusCode": 200,
                        "body": "{\"id\": #{id}, \"name\": \"#{name}\"}"
                    },
                    "_behaviors": {
                        "generate": {
                            "id": {
                                "type": "number"
                            },
                            "name": {
                                "type": "string"
                            }
                        }
                    }
                }
            ]
        }
    ]
}

That has the advantage of working with other content types (e.g. XML) and other response fields (e.g. TCP data and HTTP statusCode) in a consistent way. If more robust generation is required (including randomly including/excluding optional fields), maybe:

{
    "port": 4545,
    "protocol": "http",
    "stubs": [
        {
            "responses": [
                {
                    "is": {
                        "statusCode": 200,
                        "body": "#{order}"
                    },
                    "_behaviors": {
                        "generate": {
                            "order": {
                                "type": "json",
                                "fields": [
                                    {
                                        "name": "id",
                                        "type": "number"
                                    },
                                    {
                                        "name": "name",
                                        "type": "string",
                                        "required": false
                                    }
                                ]
                            }
                        }
                    }
                }
            ]
        }
    ]
}

Definitely open to suggestions - did you have other ideas on how to structure the API?

@moodmosaic
Copy link
Contributor Author

No, as far as I can tell - Stub resolvers decorated with a hypothetical new behavior sounds great :) I think create or build are probably more precise names for this particular behavior definition.

@bbyars
Copy link
Owner

bbyars commented May 11, 2014

Sounds good to me. If you're still interested in working on it, let me know if you need any help getting started. Definitely open to questions or even a skype if it helps.

@moodmosaic
Copy link
Contributor Author

Sounds good! Thanks, I will let you know! It might take me a couple of days before I open a pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants