GithubHelp home page GithubHelp logo

pact-foundation / pact-net Goto Github PK

View Code? Open in Web Editor NEW
821.0 45.0 225.0 18.9 MB

.NET version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.

Home Page: https://pact.io

License: MIT License

C# 99.50% Shell 0.50%
pact contract-testing apis csharp dotnet pact-net smartbear-supported

pact-net's Introduction

logo

Pact Net

Build status

Fast, easy and reliable testing for your APIs and microservices.

Pact is the de-facto API contract testing tool. Replace expensive and brittle end-to-end integration tests with fast, reliable and easy to debug unit tests.

  • ⚑ Lightning fast
  • 🎈 Effortless full-stack integration testing - from the front-end to the back-end
  • πŸ”Œ Supports HTTP/REST and event-driven systems
  • πŸ› οΈ Configurable mock server
  • 😌 Powerful matching rules prevents brittle tests
  • 🀝 Integrates with Pact Broker / PactFlow for powerful CI/CD workflows
  • πŸ”‘ Supports 12+ languages

Why use Pact?

Contract testing with Pact lets you:

  • ⚑ Test locally
  • πŸš€ Deploy faster
  • ⬇️ Reduce the lead time for change
  • πŸ’° Reduce the cost of API integration testing
  • πŸ’₯ Prevent breaking changes
  • πŸ”Ž Understand your system usage
  • πŸ“ƒ Document your APIs for free
  • πŸ—„ Remove the need for complex data fixtures
  • πŸ€·β€β™‚οΈ Reduce the reliance on complex test environments

Watch our series on the problems with end-to-end integrated tests, and how contract testing can help.

----------

Documentation

Tutorial (60 minutes)

Learn everything in Pact Net in 60 minutes

Upgrade Guides

Older Versions

Need Help

Installation

Via Nuget

----------

Usage

In the sections below, we provide a brief sample of the typical flow for Pact testing using HTTP interactions, written in the XUnit framework.

A more comprehensive example which uses both HTTP and message interactions, provider states, matchers and more can be found in the samples/OrdersApi folder.

Writing a Consumer test

Pact is a consumer-driven contract testing tool, which is a fancy way of saying that the API Consumer writes a test to set out its assumptions and needs of its API Provider(s). By unit testing our API client with Pact, it will produce a contract that we can share to our Provider to confirm these assumptions and prevent breaking changes.

In this example, we are going to be testing our User API client, responsible for communicating with the UserAPI over HTTP. It currently has a single method GetUser(id) that will return a User.

Pact tests have a few key properties. We'll demonstrate a common example using the 3A Arrange/Act/Assert pattern.

public class SomethingApiConsumerTests
{
    private readonly IPactBuilderV4 pactBuilder;

    public SomethingApiConsumerTests()
    {
        // Use default pact directory ..\..\pacts and default log
        // directory ..\..\logs
        var pact = Pact.V4("Something API Consumer", "Something API", new PactConfig());

        // or specify custom log and pact directories
        pact = Pact.V4("Something API Consumer", "Something API", new PactConfig
        {
            PactDir = $"{Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName}{Path.DirectorySeparatorChar}pacts"
        });

        // Initialize Rust backend
        this.pactBuilder = pact.WithHttpInteractions();
    }

    [Fact]
    public async Task GetSomething_WhenTheTesterSomethingExists_ReturnsTheSomething()
    {
        // Arrange
        this.pactBuilder
            .UponReceiving("A GET request to retrieve the something")
                .Given("There is a something with id 'tester'")
                .WithRequest(HttpMethod.Get, "/somethings/tester")
                .WithHeader("Accept", "application/json")
            .WillRespond()
                .WithStatus(HttpStatusCode.OK)
                .WithHeader("Content-Type", "application/json; charset=utf-8")
                .WithJsonBody(new
                {
                    id = "tester",
                    firstName = "Totally",
                    lastName = "Awesome"
                });

        await this.pactBuilder.VerifyAsync(async ctx =>
        {
            // Act
            var client = new SomethingApiClient(ctx.MockServerUri);
            var something = await client.GetSomething("tester");

            // Assert
            Assert.Equal("tester", something.Id);
        });
    }
}

----------

Verifying a Provider

A provider test takes one or more pact files (contracts) as input, and Pact verifies that your provider adheres to the contract. In the simplest case, you can verify a provider as per below. In SomethingApiFixture, the provider is started. In SomethingApiTests, the fixture is verified against the pact files.

public class SomethingApiFixture : IDisposable
{
    private readonly IHost server;
    public Uri ServerUri { get; }

    public SomethingApiFixture()
    {
        ServerUri = new Uri("http://localhost:9223");
        server = Host.CreateDefaultBuilder()
                     .ConfigureWebHostDefaults(webBuilder =>
                     {
                         webBuilder.UseUrls(ServerUri.ToString());
                         webBuilder.UseStartup<TestStartup>();
                     })
                     .Build();
        server.Start();
    }

    public void Dispose()
    {
        server.Dispose();
    }
}

public class SomethingApiTests : IClassFixture<SomethingApiFixture>
{
    private readonly SomethingApiFixture fixture;
    private readonly ITestOutputHelper output;

    public SomethingApiTests(SomethingApiFixture fixture, ITestOutputHelper output)
    {
        this.fixture = fixture;
        this.output = output;
    }

    [Fact]
    public void EnsureSomethingApiHonoursPactWithConsumer()
    {
        // Arrange
        var config = new PactVerifierConfig
        {
            Outputters = new List<IOutput>
            {
                // NOTE: PactNet defaults to a ConsoleOutput, however
                // xUnit 2 does not capture the console output, so this
                // sample creates a custom xUnit outputter. You will
                // have to do the same in xUnit projects.
                new XUnitOutput(output),
            },
        };

        string pactPath = Path.Combine("..",
                                       "..",
                                       "..",
                                       "..",
                                       "pacts",
                                       "Something API Consumer-Something API.json");

        // Act / Assert
        using var pactVerifier = new PactVerifier("Something API", config);

        pactVerifier
            .WithHttpEndpoint(fixture.ServerUri)
            .WithFileSource(new FileInfo(pactPath))
            .WithProviderStateUrl(new Uri(fixture.ServerUri, "/provider-states"))
            .Verify();
    }
}

IMPORTANT: You can't use the Microsoft.AspNetCore.Mvc.Testing library to host your API for provider tests. If your tests are using TestServer or WebApplicationFactory then these are running the API with a special in-memory test server instead of running on a real TCP socket. This means the Rust internals can't call the API and therefore all of your provider tests will fail. You must host the API on a proper TCP socket, e.g. by using the Host method shown in the sample above, so that they can be called from non-.Net code.

----------

Messaging Pacts

For writing messaging pacts instead of requests/response pacts, see the messaging pacts guide.

----------

Compatibility

Operating System

Due to using a shared native library instead of C# for the main Pact logic only certain OSs are supported:

OS Arch Support
Windows x86 ❌ No
Windows x64 βœ”οΈ Yes
Linux (libc) ARM ❌ No
Linux (libc) x86 ❌ No
Linux (libc) x64 βœ”οΈ Yes
Linux (musl) Any ❌ No
OSX x64 βœ”οΈ Yes
OSX ARM (M1/M2) βœ”οΈ Yes

Pact Specification

Version Status Spec Compatibility Install
5.x Beta 2, 3, 4 See installation
4.x Stable 2, 3 See installation
3.x Deprecated 2

Roadmap

The roadmap for Pact and Pact Net is outlined on our main website.

Contributing

See CONTRIBUTING.

pact-net's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pact-net's Issues

Missing(?) files in nuget package

I notice the pactnet.config and pactnet.pdb are not in the nuget package.

The PDB is useful for when a crash happens and users report a defect as you will get a full stack trace with line numbers making your life so much easier.

The config file has a lot of assembly binary redirects which may or may not be important.

Please add feedback on unmatched verify description

Thank you for building the pact-net.
Just a small enhancement request.
If the description in the Verify method does not exist in the pact file, currently no feedback is given.
Please enhance so that either it fails the test or prints a warning.
Thank you.

Interaction matching - body is ignored in certain cases

Hey @neilcampbell, question - would it make sense to run a match on request body even if request body for registered interaction is not specified?

Currently library will consider two requests matching even when body of the actual request is completely different (i.e. not null) from request body for registered interaction (that is null).

Schema instead of Hard Coded Values

Is there a way to test against a particular expected schema instead of hard coded values for the service results in say a Json Schema way? e.g. This array will exist and not be empty, this string will be n characters long, this property will be null, etc.

v2 Specification

Having this feature will be very useful for us. We are planning on building the regex matching to conform with the v2 spec gist.

Add the documentation xml file for intellisense support

Add the doc xml file (I know people don't like writing code comments)

The doc xml file can be used to provide intellisense support - especially useful for getting people running quickly. I (personally) find adding these things early on the project make them easier to maintain than adding them at the end.

Unable to use Verify with Basic auth credentials

I am trying to point my PactVerifier to a Pact-broker endpoint protected by basic auth. I am able to access the endpoint using any rest client (postman) by passing the credentials in the URL.
http://user:pass@pact-broker/---

But when I use the same URL in the PactUri method and then call Verify, it gives me a 401.

Looks like the HttpClient that is newed up in the PactVerifier doesn't like the credentials passed in the PactUri. Also, since the constructor is internal, there is no way to externally inject the httpclient with configured auth header.

Any ideas/examples of how we can use the pact-broker behind basic auth security?
Any help is highly appreciated. Thanks

Partial matching, pact .net

Hi Guys,

I have a JSON pact file with href links that is part of the response body from the consumer. Which looks something like this:

"links": [
{
"rel": [
"self",
"paymentDetail"
],
"href": "/api/uk/account/12345/payment-detail"**
}
]
},

However the provider responds with the full resource as below:

"href": "http://localhost:12345/api/uk/customeraccount/123456/payment-detail"

Therefore when I run the provider test and it compares the actual to expected it fails. I am using Pact. Net version 1.1.0 which does not support partial matching as of yet. Is there a work around that anyone knows off that could assist me in which the consumer can ignore the server name?

Regards,
Newbiee

Pacts are not being created

Hi. I'm struggling with generating pact file. Either I set PactDir path manually or leave it as default, .json file is not being created. However log file is generated successfully every time. I run test within Resharper and it passes. Any idea what might be wrong?
PactBuilder = new PactBuilder(new PactConfig { PactDir = @"..\..\pacts", LogDir = @"..\..\logs" });

Thread safety issue on the logger

There is currently a thread safety issue in the consumer debug logging when a test suite contains multiple mock providers and the tests are run in parallel.

To work around this temporarily, disable parallel test execution. However a fix will be released very soon.

Add ability to verify each interaction in a separate test

At the moment there is a couple of problems with current 'verify all interactions in one test' approach:

  • it's tricky to debug since there is no easy way to isolate test scope to one particular interaction
  • developers need to remember that mocks and expectations need to be reset in teardown action for interaction - would be nice to be able to follow conventions of used test frameworks

Upgrading dependencies seems to cause issues

Going back to pull-request #71 I have managed to recreate a similar issue, I have created a repository here

When running the test I get the error message:

System.IO.FileLoadException : Could not load file or assembly 'System.IO.Abstractions, Version=1.4.0.86, Culture=neutral, PublicKeyToken=d480b5b72fb413da' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
at PactNet.Infrastructure.Logging.LocalRollingLogFileMessageHandler..ctor(String logFilePath)
at PactNet.Infrastructure.Logging.LocalLogProvider.AddLogger(String logDir, String loggerNameSeed, String logFileNameTemplate) in C:\projects\pact-net\PactNet\Infrastructure\Logging\LocalLogProvider.cs:line 36
at PactNet.Infrastructure.Logging.LocalLogProvider.AddLogger(String logDir, String loggerNameSeed, String logFileNameTemplate) in C:\projects\pact-net\PactNet\Infrastructure\Logging\LocalLogProvider.cs:line 37
at PactNet.Infrastructure.Logging.LocalLogProvider.AddLogger(String logDir, String loggerNameSeed, String logFileNameTemplate) in C:\projects\pact-net\PactNet\Infrastructure\Logging\LocalLogProvider.cs:line 37
at PactNet.Infrastructure.Logging.LocalLogProvider.AddLogger(String logDir, String loggerNameSeed, String logFileNameTemplate) in C:\projects\pact-net\PactNet\Infrastructure\Logging\LocalLogProvider.cs:line 37
at PactNet.Mocks.MockHttpService.Nancy.NancyHttpHost..ctor(Uri baseUri, String providerName, PactConfig config, Boolean bindOnAllAdapters) in C:\projects\pact-net\PactNet\Mocks\MockHttpService\Nancy\NancyHttpHost.cs:line 27
at PactNet.Mocks.MockHttpService.MockProviderService.<>c__DisplayClass13_0.<.ctor>b__0(Uri baseUri) in C:\projects\pact-net\PactNet\Mocks\MockHttpService\MockProviderService.cs:line 45
at PactNet.Mocks.MockHttpService.MockProviderService.Start() in C:\projects\pact-net\PactNet\Mocks\MockHttpService\MockProviderService.cs:line 129
at PactNet.PactBuilder.MockService(Int32 port, JsonSerializerSettings jsonSerializerSettings, Boolean enableSsl, Boolean bindOnAllAdapters) in C:\projects\pact-net\PactNet\PactBuilder.cs:line 78
at PactNet.PactBuilder.MockService(Int32 port, Boolean enableSsl, Boolean bindOnAllAdapters) in C:\projects\pact-net\PactNet\PactBuilder.cs:line 58
at PactNetTests.ContractTest.SetUp()

Setup builds

Have a discussion about if we want to use TC or use something like travis-ci.org? We could also generate a hook to auto publish to the nuget.org package feed, when commits have been merged into master.

Create nuget package

Create nuget package and publish to nuget.org feed, we may also decide to IL merge or include the thirdy party assemblies as resource rather than nuget dependencies.

Indirect dependency error message

HI there
I've recently spent some time grappling with mysterious error messages and persuading a solution to build. I didn't find anything on the internet about it, so I thought I would report it here.
When I first added Pact.Net to my solution everything went very smoothly. I then came back to it a few weeks later, I think having changed absolutely nothing and it wouldn't build. The error messages in visual studio are basically meaningless, but there is something a tiny bit more useful in the build output, as follows:
The primary reference β€œblah.dll” could not be resolved because it has an indirect dependency on the framework assembly β€œSystem.Net.Http, Version=2.2.28.0, Culture=neutral, PublicKey Token=b03f5f7f11d50a3a” which could not be resolved in the currently targeted framework. β€œ.NETFramework, Version=v4.0”. To resolve this problem, either remove the reference β€œblah.dll” or retarget your application to a framework version which contains β€œSystem.Net.Http, Version=2.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”
After a lot of fiddling it turns out that you need to nuget install-package Microsoft.Net.Http 2.2.28.0 on all projects that reference a project, that contains a reference to pact.net.
This isn't the latest version of the library, and looking at the Pact.Net source there are no "Use Specific Version" references to this, so it's all a bit confusing. I think it might be because the Microsoft.Bcl package references System.Net.Http, but I didn't get to the bottom of it.
Cheers
Cedd

Does not work with Nancy 1.4.3

Hi,
I had the last Nancy 1.4.3 and the consumer test was raising an exception (timeout on the ClearInteractions). I have checked all other dependencies but it fails because of Nancy: it works with the 0.23.1. I did not check with other versions. At least you should update the documentation.

Btw, thank you for this very nice library.
Xavier

Generated ID as part of the path

Hi,

I'm trying to build pacts that have randomly generated unique IDs in the path. Example:

  "request": {
    "method": "get",
    "path": "/groups/d6a61741-203a-4b8a-aec1-c9db15cff87b/messages/8a975ddf-1786-48a8-b835-8f7f578afbf1/locations",
    "headers": {
      "Accept": "application/json"
    }
  },

Is this possible to do this using PactNet? Does it matter that it is Pact 1.1 Specification - am I required to use Pact 2 Specification compatible tools/platforms for regular expressions to be part of the path? Or is it the case that the "path" can never be this dynamic, regardless of the Pact Specification version?

Thanks a bunch.
-Jon

How to configure Pact File generation folder

Hello, I am working on generating a pact file at the moment, which works fine when I run my tests in my project from Visual Studio. However, when I run those same tests from the command line as an administrator, no pact file is generated. I was hoping this could work from the command line (currently using MsTest.exe) so the build process could generate a pact. As a side note, the pact file would normally generate under the folder Api.Tests, which I assume is because it is the root folder of my test project. Any insight on this would be appreciated.

cmd

Thanks!

Using service references

100% if my .net c# integration is done through 'service references' and SOAP messages.
I tried to use pact-net with no success. Is it supported? Will it be? What has to be done? Nothing in readme...

Ability to set JSON serialization settings

I've noticed that the default serialization settings for the request body currently do not serialize null values.

Some rest clients, however, notably RestSharp, do serialize null values and do not directly give you the option to change these settings. You can get over it by serializing manually using something like JSON.NET in your client.

Could we possibly be able to tweak the serialization settings so that a body can match based on the preferred serialization settings of the app, rather than PACT's preferred settings? Not sure whether you think this is a good idea....

[Idea] Automatic record/replay mocks

We recently started using pact-net at work and I'm slightly bothered by how much manual work is involved in creating the mocks and handling the resulting files.

I was thinking whether it would be a good idea (and whether someone thought about it) to create some sort of proxy generic mock which could be started in "record mode" and to which we would then direct our services. This proxy mock would (based on a config file) forward the requests to the actual service and then transport the response back to the actual service. This request/response interaction pair could then be saved as, e.g., a JSON file. Then, we would be able to start the proxy mock in a "replay mode" where it's simply replying to requests based on what it has recorded. This way we would avoid having to write the mock services ourselves and instead take the current snapshot of the provider as the "valid contract" upon which we base all our future test runs.

Has anyone thought about this? Do you see value on it if, e.g., I was to work on something along these lines?

PACT working with tokens

Haven't thought a lot about this yet - but has anyone got PACT working with access/identity tokens in headers?

Consumers will have tokens in the request headers, but ensuring they remain valid on the provider side in tests.

Is there anyway of replacing the token in the pact request on the provider side?

Remove statics on MockProviderNancyRequestDispatcher

There is some nasty static stuff on the MockProviderNancyRequestDispatcher, which basically means that Parallel tests will fail. We cannot use ThreadStatic as the request dispatcher will run in the nancy thread and the state will not be setup correctly for the test.

We can either:

  1. Hold a collection of expectedRequest/Responses
  2. Remove static state all together in some way (preferred)

Add provider verification mechanism

Provide a mechanism to verify if the provider was called in the way we expected during the test. The ruby library also looks to allow configuration of verifications, so it may be a nice extension point too.

Add a 'readme' to the nuget package

The 'readme' should provide a getting started guide and maybe even a sample to help users quickly get to grips with PACT (.NET).

It would probably be something very similar to the readme.md or even refer to the readme.md :)

Is RestSharp supported?

I noticed that you're using System.Net.Http.HttpClient in your examples. Is RestSharp supported as an alternative client library?

I'm confused about how to generate the json pact file. I have created a pact consumer test project that contains a Pact class, which implements IDisposable(), which calls PactBuilder.Build(), but I can't figure out where the file is being written to. The documentation doesn't describe this anywhere, and when I look at the source code I can't find the code that writes the file. I'm running on Windows 10. Can you point me to where the file is/should-be written to? Or, do I have to create the file manually?

Make test output better

The current test output mechanism is fairly primitive and could be a lot better!

I would be nice to use a Reporter abstraction and come up with a nice way of reporting failures. BDDfy may be a good place to start for inspiration.

Working with types or regex

Hi Guys,

Where can I find samples of how to create the pact file with types instead of fixed values?

I wan tot use this in a project, but I won't be able to unless I can find a way to work with types instead of fixed data.

Thanks,

Karl

Can PactConfig.LoggerName be made public?

When using MockProviderNancyBootstrapper it needs the PactConfig.LoggerName to be set and it can't be set when creating PactConfig in an external assembly because it's currently set to be internal.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.