NetMock is a .NET network service mock framework, inspired by Moq syntax, providing the ability to mock REST and web socket APIs from within a test framework of choice.
A set of examples to show usage and possibilities are part of the solution, available here.
The following table shows the implementation status of currenly planned features.
Component | Feature | Status |
---|---|---|
Configuration | ActivationStrategy { Manual, AutomaticOnCreation } (default is AutomaticOnCreation ) |
✓ |
MockBehavior { Loose, Strict } (default is Loose ) |
✓ | |
PrintReceivedRequestsOnTearDown (default is false ) |
✓ | |
Mock creation | CreateRestMock(int port, MockBehavior mockBehavior) |
✓ |
CreateRestMock(string basePath, int port, MockBehavior mockBehavior) |
✓ | |
CreateSecureRestMock(int port, X509FindType certificateFindType, string certificateFindValue, StoreName storeName, StoreLocation storeLocation, MockBehavior mockBehavior) |
✓ | |
CreateSecureRestMock(string basePath, int port, X509FindType certificateFindType, string certificateFindValue, StoreName storeName, StoreLocation storeLocation, MockBehavior mockBehavior) |
✓ | |
CreateSecureRestMock(int port, X509Certificate2 certificate, MockBehavior mockBehavior) |
✓ | |
CreateSecureRestMock(string basePath, int port, X509Certificate2 certificate, MockBehavior mockBehavior) |
✓ |
Component | Feature | Status |
---|---|---|
HTTP methods | Get , Post , Put , Patch , Delete , Head , Options , Trace , Connect |
✓ |
Configuration | StaticHeaders |
✓ |
DefaultResponseStatusCode (default is NotImplemented ) |
✓ | |
UndefinedQueryParameterHandling { Ignore, Fail } (default is Fail ) |
✓ | |
UndefinedHeaderHandling { Ignore, Fail } (default is Ignore ) |
✓ | |
MockBehavior { Loose, Strict } (default is Loose ) |
✓ | |
InterpretBodyAsJson (default is true ) |
✓ | |
Request setup | Setup(Method method, string path, params IMatch[] matches) |
✓ |
SetupGet(string path, params IMatch[] matches) |
✓ | |
SetupPost(string path, params IMatch[] matches) |
✓ | |
SetupPut(string path, params IMatch[] matches) |
✓ | |
SetupPatch(string path, params IMatch[] matches) |
✓ | |
SetupDelete(string path, params IMatch[] matches) |
✓ | |
SetupHead(string path, params IMatch[] matches) |
✓ | |
SetupOptions(string path, params IMatch[] matches) |
✓ | |
SetupTrace(string path, params IMatch[] matches) |
✓ | |
SetupConnect(string path, params IMatch[] matches) |
✓ | |
Request verification | Verify(Method method, string path, params IMatch[] matches, Times times) |
✓ |
VerifyGet(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyPost(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyPut(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyPatch(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyDelete(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyHead(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyOptions(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyTrace(string path, params IMatch[] matches, Times times) |
✓ | |
VerifyConnect(string path, params IMatch[] matches, Times times) |
✓ | |
Response setup | Returns(params AttachedHeader[] headers) |
✓ |
Returns(int statusCode, params AttachedHeader[] headers) |
✓ | |
Returns(HttpStatusCode statusCode, params AttachedHeader[] headers) |
✓ | |
Returns(object body, params AttachedHeader[] headers) |
✓ | |
Returns(int statusCode, object body, params AttachedHeader[] headers) |
✓ | |
Returns(HttpStatusCode statusCode, object body, params AttachedHeader[] headers) |
✓ | |
Returns(Func<int> statusCodeProvider) |
✓ | |
Returns(Func<IReceivedRequest, int> statusCodeProvider) |
✓ | |
Returns(Func<HttpStatusCode> statusCodeProvider) |
✓ | |
Returns(Func<IReceivedRequest, HttpStatusCode> statusCodeProvider) |
✓ | |
Returns(Func<object> bodyProvider) |
✓ | |
Returns(Func<IReceivedRequest, object> bodyProvider) |
✓ | |
Returns(Func<IEnumerable<AttachedHeader>> headersProvider) |
✓ | |
Returns(Func<IReceivedRequest, IEnumerable<AttachedHeader>> headersProvider) |
✓ | |
Returns(Func<(int StatusCode, object Body)> responseProvider) |
✓ | |
Returns(Func<IReceivedRequest, (int StatusCode, object Body)> responseProvider) |
✓ | |
Returns(Func<(HttpStatusCode StatusCode, object Body)> responseProvider) |
✓ | |
Returns(Func<IReceivedRequest, (HttpStatusCode StatusCode, object Body)> responseProvider) |
✓ | |
Returns(Func<(int StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns(Func<IReceivedRequest, (int StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns(Func<(HttpStatusCode StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns(Func<IReceivedRequest, (HttpStatusCode StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns(Func<(object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns(Func<IReceivedRequest, (object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns<T1>(Func<T1, int> statusCodeProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, int> statusCodeProvider) |
✓ | |
Returns<T1>(Func<T1, HttpStatusCode> statusCodeProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, HttpStatusCode> statusCodeProvider) |
✓ | |
Returns<T1>(Func<T1, object> bodyProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, object> bodyProvider) |
✓ | |
Returns<T1>(Func<T1, IEnumerable<AttachedHeader>> headersProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, IEnumerable<AttachedHeader>> headersProvider) |
✓ | |
Returns<T1>(Func<T1, (int StatusCode, object Body)> responseProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, (int StatusCode, object Body)> responseProvider) |
✓ | |
Returns<T1>(Func<T1, (HttpStatusCode StatusCode, object Body)> responseProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, (HttpStatusCode StatusCode, object Body)> responseProvider) |
✓ | |
Returns<T1>(Func<T1, (int StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, (int StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns<T1>(Func<T1, (HttpStatusCode StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, (HttpStatusCode StatusCode, object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns<T1>(Func<T1, (object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Returns<T1>(Func<IReceivedRequest, T1, (object Body, IEnumerable<AttachedHeader> Headers)> responseProvider) |
✓ | |
Above generic signatures with generic arguments ranging up to T9 (additional 144 overloads) | ✓ | |
Callback(Action callback) |
✓ | |
Callback(Action<IReceivedRequest> callback) |
✓ | |
Callback<T1>(Action<T1> callback) |
✓ | |
Callback<T1>(Action<IReceivedRequest, T1> callback) |
✓ | |
Above generic signatures with generic arguments ranging up to T9 (additional 16 overloads) | ✓ | |
Parameter matching | Parameter.Is<TValue>(string name, TValue value) |
✓ |
Parameter.Is<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Parameter.Is(string name, Func<string, bool> condition) |
✓ | |
Parameter.Is<TValue>(string name, Func<TValue, bool> condition) |
✓ | |
Parameter.IsNot<TValue>(string name, TValue value) |
✓ | |
Parameter.IsNot<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Parameter.IsAny(string name) |
✓ | |
Parameter.IsAny<TValue>(string name) |
✓ | |
Parameter.StartsWith<TValue>(string name, TValue value) |
✓ | |
Parameter.StartsWith<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Parameter.EndsWith<TValue>(string name, TValue value) |
✓ | |
Parameter.EndsWith<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Parameter.Contains<TValue>(string name, TValue value) |
✓ | |
Parameter.Contains<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Parameter.NotContains<TValue>(string name, TValue value) |
✓ | |
Parameter.NotContains<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Parameter.StartsWithWord<TValue>(string name, TValue word) |
✓ | |
Parameter.StartsWithWord<TValue>(string name, TValue word, CompareCase compareCase) |
✓ | |
Parameter.EndsWithWord<TValue>(string name, TValue word) |
✓ | |
Parameter.EndsWithWord<TValue>(string name, TValue word, CompareCase compareCase) |
✓ | |
Parameter.ContainsWord<TValue>(string name, TValue word) |
✓ | |
Parameter.ContainsWord<TValue>(string name, TValue word, CompareCase compareCase) |
✓ | |
Parameter.NotContainsWord<TValue>(string name, TValue word) |
✓ | |
Parameter.NotContainsWord<TValue>(string name, TValue word, CompareCase compareCase) |
✓ | |
Header matching | Header.Is<TValue>(string name, TValue value) |
✓ |
Header.Is<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Header.Is(string name, Func<string, bool> condition) |
✓ | |
Header.Is<TValue>(string name, Func<TValue, bool> condition) |
✓ | |
Header.IsNot<TValue>(string name, TValue value) |
✓ | |
Header.IsNot<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Header.IsSet(string name) |
✓ | |
Header.IsNotSet(string name) |
✓ | |
Header.Contains<TValue>(string name, TValue value) |
✓ | |
Header.Contains<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Header.NotContains<TValue>(string name, TValue value) |
✓ | |
Header.NotContains<TValue>(string name, TValue value, CompareCase compareCase) |
✓ | |
Body matching | Body.Is<TValue>(TValue value) |
✓ |
Body.Is<TValue>(TValue value, CompareCase compareCase) |
✓ | |
Body.Is(Func<string, bool> condition) |
✓ | |
Body.Is<TValue>(Func<TValue, bool> condition) |
✓ | |
Body.IsNot<TValue>(TValue value) |
✓ | |
Body.IsNot<TValue>(TValue value, CompareCase compareCase) |
✓ | |
Body.IsAny() |
✓ | |
Body.IsAny<TValue>() |
✓ | |
Body.IsEmpty() |
✓ | |
Body.IsNotEmpty() |
✓ | |
Body.Contains<TValue>(TValue value) |
✓ | |
Body.Contains<TValue>(TValue value, CompareCase compareCase) |
✓ | |
Body.NotContains<TValue>(TValue value) |
✓ | |
Body.NotContains<TValue>(TValue value, CompareCase compareCase) |
✓ | |
Body.ContainsWord<TValue>(TValue word) |
✓ | |
Body.ContainsWord<TValue>(TValue word, CompareCase compareCase) |
✓ | |
Body.NotContainsWord<TValue>(TValue word) |
✓ | |
Body.NotContainsWord<TValue>(TValue word, CompareCase compareCase) |
✓ | |
Verification hit count matching | Times.Never |
✓ |
Times.Once |
✓ | |
Times.Twice |
✓ | |
Times.AtLeastOnce |
✓ | |
Times.AtMostOnce |
✓ | |
Times.Exactly(int callCount) |
✓ | |
Times.AtLeast(int callCount) |
✓ | |
Times.AtMost(int callCount) |
✓ | |
Times.Between(int callCountFrom, int callCountTo) |
✓ |
No implementation started.
// arrange
ServiceMock serviceMock = new ServiceMock();
RestMock restMock = serviceMock.CreateRestMock("/api/v1", 9001, useSSL: false);
restMock.Setup(Method.Get, "/alive").Returns(new AliveMessage());
serviceMock.Activate();
// act
...
// assert
restMock.Verify(Method.Get, "/alive", Times.Once);
// teardown
serviceMock.Teardown();
// arrange
ServiceMock serviceMock = new ServiceMock();
serviceMock.InstallCerts(certFile);
RestMock restMock = serviceMock.CreateRestMock("/api/v1", 9001, useSSL: true);
restMock.Setup(Method.Post, "/user", body: new User() { UserId = "abc" })
.Returns(new User() { ID = new Guid("698fa58a-8e9c-4607-b6c3-b5da19751a04"), UserId = "abc" });
serviceMock.Activate();
// act
...
// assert
restMock.Verify(Method.Post, "/user", Times.Once)
// teardown
serviceMock.Teardown();
// arrange
ServiceMock serviceMock = new ServiceMock();
serviceMock.InstallCerts(certFile);
RestMock restMock = serviceMock.CreateRestMock("/api/v1", 9001, useSSL: true);
restMock.Setup(Method.Post, "/user", body: "{ 'userId' = 'abc' }")
.Returns("{ 'id' = '698fa58a-8e9c-4607-b6c3-b5da19751a04', 'userId' = 'abc' }");
restMock.Setup(Method.Post, "/user", body: "{ 'userId' = 'xyz' }")
.Returns("{ 'id' = '607a755d-3ded-4a42-9a96-03d9ecfd31da', 'userId' = 'xyz' }");
serviceMock.Activate();
// act
...
// assert
restMock.Verify(Method.Post, "/user", Times.Twice);
restMock.Verify(Method.Post, "/user", body: "{ 'userId' = 'abc' }", Times.Once);
restMock.Verify(Method.Post, "/user", body: "{ 'userId' = 'xyz' }", Times.Once);
// teardown
serviceMock.Teardown();
// arrange
int getUserCallCount = 0;
string encryptedConnectionString = "...";
ServiceMock serviceMock = new ServiceMock();
serviceMock.InstallCerts(certFile);
RestMock restMock = serviceMock.CreateRestMock("/api/v1", 9001, useSSL: true);
restMock.Setup(Method.Post, "/user", body: "{ 'userId' = '' }")
.ReturnsError(400);
restMock.Setup(Method.Post, "/user", body: "{ 'userDirectory' = '' }")
.ReturnsError(400, body: "User directory missing, what were you thinking?");
restMock.Setup(Method.Get, "/user/{id}", Parameter.Is("id", "698fa58a-8e9c-4607-b6c3-b5da19751a04"))
.Returns(new User() { ID = new Guid("698fa58a-8e9c-4607-b6c3-b5da19751a04"), UserId = "abc" });
restMock.Setup(Method.Get, "/user")
.Callback(() => { getUserCallCount++; });
restMock.Setup(Method.Get, "/user/detail?filter={filter}&orderby={orderby}",
Parameter.Is("filter", "userDirectory eq 'acme'", CompareCase.Insensitive),
Parameter.EndsWithWord("orderby", "desc", CompareCase.Insensitive))
.Returns(new[]
{
new User() { ID = new Guid("607a755d-3ded-4a42-9a96-03d9ecfd31da"), UserId = "xyz", UserDirectory = "ACME" },
new User() { ID = new Guid("698fa58a-8e9c-4607-b6c3-b5da19751a04"), UserId = "abc", UserDirectory = "ACME" }
});
restMock.Setup(Method.Get, "/product?filter={filter}&orderby={orderby}",
Parameter.Is("filter", filter => filter.Split(' ').Any(word => word.ToLower() == "and")),
Parameter.IsAny("orderby"))
.ReturnsError(500);
restMock.Setup(Method.Get, "/secure/item",
Header.Is("X-Acme-User", "UserDirectory=INTERNAL; UserId=sa", CompareCase.Insensitive))
.Returns(new[] { new DataConnection() { Connectionstring = Decrypt(encryptedConnectionString) } },
Header.Attach("Cache-Control", "private"));
restMock.Setup(Method.Get, "/secure/item",
Header.IsNot("X-Acme-User", "UserDirectory=INTERNAL; UserId=sa", CompareCase.Insensitive),
Header.IsNotSet("X-Acme-Security"))
.Returns(new[] { new DataConnection() { Connectionstring = encryptedConnectionString } });
serviceMock.Activate();
// act
...
// assert
Assert.AreEqual(5, getUserCallCount);
restMock.Verify(Method.Get, "/user/detail?filter={filter}&orderby={orderby}", Times.Never,
Parameter.IsAny("filter"),
Parameter.ContainsWord("orderby", "userDirectory", CompareCase.Insensitive));
// teardown
serviceMock.Teardown();