Skip to content

Commit ee2dbb5

Browse files
committed
First version of endpoint testing
1 parent 501602a commit ee2dbb5

File tree

7 files changed

+247
-32
lines changed

7 files changed

+247
-32
lines changed

UnitTests/TestTestCommand.cs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,22 @@ public static class TESTCOMMAND_CONSTANTS
4343
'requestpath': '/foo/',
4444
'requestbody': 'heisann test',
4545
'expectedresponsebody': 'FOOBARBOOBAR'
46-
}
46+
},
47+
48+
{
49+
'name': '/foo/ request works',
50+
'requestpath': '/foo/',
51+
'requestbody': 'heisann test',
52+
'expectedresponsebody': 'file:example.txt'
53+
},
54+
55+
{
56+
'name': '/foo/ request works',
57+
'requestpath': '/foo/',
58+
'requestbody': 'file:example.txt',
59+
'expectedresponsebody': 'file:example.txt',
60+
},
61+
4762
]
4863
";
4964

@@ -87,6 +102,7 @@ public TestTestCommand()
87102
dc.AddFile("endpoint1\\endpoint.json", TESTCOMMAND_CONSTANTS.ENDPOINTJSON);
88103
dc.AddFile("endpoint1\\content.txt", "FOOBARBOOBAR");
89104
dc.AddFile("tests\\tests.json", TESTCOMMAND_CONSTANTS.TESTS);
105+
dc.AddFile("tests\\example.txt", "FOOBARBOOBAR");
90106
}
91107

92108
public void Dispose()
@@ -105,14 +121,22 @@ public void DetectsTestSuite()
105121
public void CanReadTestsFromJSONFile()
106122
{
107123
var endpointTestDefinition = EndpointTestDefinition.ReadFromDirectory(dc.DirectoryName);
108-
Assert.Equal(1, endpointTestDefinition.Tests.Count());
124+
Assert.Equal(3, endpointTestDefinition.Tests.Count());
109125
var test = endpointTestDefinition.Tests.ElementAt(0);
110126
Assert.Equal("/foo/ request works", test.Name);
111127
Assert.Equal("/foo/", test.RequestPath);
112128
Assert.Equal("heisann test", test.RequestBody);
113129
Assert.Equal("FOOBARBOOBAR", test.ExpectedResponseBody);
114130
}
115131

132+
[Fact]
133+
public void RequestBodyCanBeReadFromFile()
134+
{
135+
var endpointTestDefinition = EndpointTestDefinition.ReadFromDirectory(dc.DirectoryName);
136+
var test = endpointTestDefinition.Tests.ElementAt(2);
137+
Assert.Equal("FOOBARBOOBAR", test.RequestBody);
138+
}
139+
116140
[Fact]
117141
async public void CanExecuteTest()
118142
{
@@ -122,5 +146,69 @@ async public void CanExecuteTest()
122146
var result = await test.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName), handleErrors: false);
123147
Assert.True(result.OK);
124148
}
149+
150+
[Fact]
151+
async public void CanReadExpectedResponseBodyFromFile()
152+
{
153+
var endpointTestDefinition = EndpointTestDefinition.ReadFromDirectory(dc.DirectoryName);
154+
var test = endpointTestDefinition.Tests.ElementAt(1);
155+
156+
var result = await test.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName), handleErrors: false);
157+
Assert.True(result.OK, result.Message);
158+
}
159+
160+
[Fact]
161+
async public void CanCheckExpectedRequestMatcherError()
162+
{
163+
var testcase =
164+
(new JSONTest { name="checksomething", requestpath = "/foo/", requestbody = "foobar", expectedrequestmatcher = "Regex 'test'" })
165+
.Validated().CreateTestCase(".");
166+
167+
Assert.True(testcase.HasExpectations);
168+
Assert.False(testcase.NeedsResponseBody);
169+
Assert.Equal("Regex 'test'", testcase.ExpectedRequestMatcher);
170+
Assert.Equal("foobar", testcase.RequestBody);
171+
172+
var result = await testcase.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName));
173+
Assert.True(result.Error);
174+
Assert.Null(result.Exception);
175+
Assert.Equal("Expected request matcher: Regex 'test'\nActual: Any request", result.Message);
176+
}
177+
178+
[Fact]
179+
async public void CanCheckExpectedRequestMatcherSuccess()
180+
{
181+
var testcase =
182+
(new JSONTest { name = "checksomething", requestpath = "/foo/", requestbody = "this is a test", expectedrequestmatcher = "Regex 'test'" })
183+
.Validated().CreateTestCase(".");
184+
var result = await testcase.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName));
185+
Assert.True(result.OK);
186+
}
187+
188+
[Fact]
189+
async public void CanCheckExpectedResponseCreatorFailureError()
190+
{
191+
var testcase =
192+
(new JSONTest { name = "checksomething", requestpath = "/foo/", requestbody = "foobar", expectedresponsecreator = "File content.txt" })
193+
.Validated().CreateTestCase(".");
194+
Assert.True(testcase.HasExpectations);
195+
Assert.False(testcase.NeedsResponseBody);
196+
Assert.Equal("File content.txt", testcase.ExpectedResponseCreator);
197+
var result = await testcase.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName));
198+
Assert.True(result.Error);
199+
Assert.Equal("Expected response creator: File content.txt\nActual: Execute script myscript.csscript", result.Message);
200+
}
201+
202+
[Fact]
203+
async public void CanCheckExpectedResponseCreatorFailureSuccess()
204+
{
205+
var testcase =
206+
(new JSONTest { name = "checksomething", requestpath = "/foo/", requestbody = "this is a test", expectedresponsecreator = "File content.txt" })
207+
.Validated().CreateTestCase(".");
208+
Assert.Equal("File content.txt", testcase.ExpectedResponseCreator);
209+
var result = await testcase.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName));
210+
Assert.True(result.OK, result.Message);
211+
Assert.Null(result.Message);
212+
}
125213
}
126214
}

netmockery/DynamicResponseCreator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public FileDynamicResponseCreator(string filename)
131131

132132
public override string FileSystemDirectory => Path.GetDirectoryName(Filename);
133133

134-
public override string ToString() => $"Execute script {_filename}";
134+
public override string ToString() => $"Execute script {Path.GetFileName(_filename)}";
135135
}
136136

137137
public class AssemblyResponseCreator : SimpleResponseCreator

netmockery/EndpointTestDefinition.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ static public bool HasTestSuite(string directory)
2222
return File.Exists(tests_json_filename(directory));
2323
}
2424

25-
static private string tests_json_filename(string directory) => Path.Combine(directory, "tests", "tests.json");
25+
static private string tests_directory(string directory) => Path.Combine(directory, "tests");
26+
27+
static private string tests_json_filename(string directory) => Path.Combine(tests_directory(directory), "tests.json");
2628

2729
public static EndpointTestDefinition ReadFromDirectory(string directory)
2830
{
2931
var jsonTests = JsonConvert.DeserializeObject<List<JSONTest>>(File.ReadAllText(tests_json_filename(directory)));
30-
return new EndpointTestDefinition(from jsontest in jsonTests select jsontest.CreateTestCase());
32+
return new EndpointTestDefinition(from jsontest in jsonTests select jsontest.Validated().CreateTestCase(tests_directory(directory)));
3133
}
3234
}
3335
}

netmockery/JSONReader.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,46 @@ public class JSONTest
2727
public string requestpath;
2828
public string requestbody;
2929
public string expectedresponsebody;
30+
public string expectedrequestmatcher;
31+
public string expectedresponsecreator;
32+
public string expectedrequestcreator;
3033

31-
public NetmockeryTestCase CreateTestCase()
34+
public JSONTest Validated()
3235
{
3336
if (requestpath == null)
3437
{
3538
throw new ArgumentNullException(nameof(requestpath));
3639
}
37-
return new NetmockeryTestCase { Name = name, RequestPath = requestpath, RequestBody = requestbody ?? "", ExpectedResponseBody = expectedresponsebody };
40+
if (name == null)
41+
{
42+
throw new ArgumentNullException(nameof(name));
43+
}
44+
45+
return this;
46+
}
47+
48+
public NetmockeryTestCase CreateTestCase(string directory)
49+
{
50+
return new NetmockeryTestCase {
51+
Name = name,
52+
RequestPath = requestpath,
53+
RequestBody =
54+
requestbody != null && requestbody.StartsWith("file:")
55+
?
56+
File.ReadAllText(Path.Combine(directory, requestbody.Substring(5)))
57+
:
58+
requestbody,
59+
60+
ExpectedRequestMatcher = expectedrequestmatcher,
61+
ExpectedResponseCreator = expectedresponsecreator,
62+
63+
ExpectedResponseBody =
64+
expectedresponsebody != null && expectedresponsebody.StartsWith("file:")
65+
?
66+
File.ReadAllText(Path.Combine(directory, expectedresponsebody.Substring(5)))
67+
:
68+
expectedresponsebody
69+
};
3870
}
3971
}
4072

netmockery/NetmockeryTestCase.cs

Lines changed: 116 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,57 @@ public class NetmockeryTestCase
7373
public string Name;
7474
public string RequestPath;
7575
public string RequestBody;
76-
public string ExpectedResponseBody;
76+
77+
public string ExpectedRequestMatcher;
78+
public string ExpectedResponseCreator;
79+
80+
public string ExpectedResponseBody;
81+
82+
public bool NeedsResponseBody
83+
{
84+
get
85+
{
86+
return (new[] { ExpectedResponseBody }).Any(val => val != null);
87+
}
88+
}
89+
90+
public bool HasExpectations
91+
{
92+
get
93+
{
94+
return (new[] { ExpectedResponseBody, ExpectedRequestMatcher, ExpectedResponseCreator }).Any(val => val != null);
95+
}
96+
}
97+
98+
99+
public bool Evaluate(string requestMatcher, string responseCreator, string responseBody, out string message)
100+
{
101+
Debug.Assert(responseBody != null || !NeedsResponseBody);
102+
Debug.Assert(requestMatcher != null);
103+
Debug.Assert(responseCreator != null);
104+
message = null;
105+
106+
if (ExpectedRequestMatcher != null && ExpectedRequestMatcher != requestMatcher)
107+
{
108+
message = $"Expected request matcher: {ExpectedRequestMatcher}\nActual: {requestMatcher}";
109+
return false;
110+
}
111+
112+
if (ExpectedResponseCreator != null && ExpectedResponseCreator != responseCreator)
113+
{
114+
message = $"Expected response creator: {ExpectedResponseCreator}\nActual: {responseCreator}";
115+
return false;
116+
}
117+
118+
if (ExpectedResponseBody != null && ExpectedResponseBody != responseBody)
119+
{
120+
message = $"Expected response body:\n{ExpectedResponseBody}\n\nActual response body:\n{responseBody}";
121+
return false;
122+
}
123+
124+
Debug.Assert(message == null);
125+
return true;
126+
}
77127

78128
async public Task<NetmockeryTestCaseResult> ExecuteAsync(EndpointCollection endpointCollection, bool handleErrors=true)
79129
{
@@ -85,8 +135,7 @@ async public Task<NetmockeryTestCaseResult> ExecuteAsync(EndpointCollection endp
85135
var endpoint = endpointCollection.Resolve(RequestPath);
86136
if (endpoint == null)
87137
{
88-
retval.Message = "No endpoint matches request path";
89-
retval.Error = true;
138+
retval.SetFailure("No endpoint matches request path");
90139
}
91140
else
92141
{
@@ -95,42 +144,79 @@ async public Task<NetmockeryTestCaseResult> ExecuteAsync(EndpointCollection endp
95144
if (matcher_and_creator != null)
96145
{
97146
var responseCreator = matcher_and_creator.Item2;
98-
var response = new TestCaseHttpResponse();
99-
var responseBodyBytes = await responseCreator.CreateResponseAsync(new TestCaseHttpRequest(RequestPath), Encoding.UTF8.GetBytes(RequestBody), response, endpoint.Directory);
100-
var responseBody = Encoding.UTF8.GetString(responseBodyBytes);
101-
retval.OK = responseBody == ExpectedResponseBody;
102-
retval.Error = !retval.OK;
103-
104-
if (retval.Error)
147+
string responseBody = null;
148+
if (! HasExpectations)
105149
{
106-
retval.Message = $"Expected response body:\n{ExpectedResponseBody}\n\nActual response body:\n{responseBody}";
150+
retval.SetFailure("Test case has no expectations");
151+
}
152+
else
153+
{
154+
if (NeedsResponseBody)
155+
{
156+
var responseBodyBytes = await responseCreator.CreateResponseAsync(new TestCaseHttpRequest(RequestPath), Encoding.UTF8.GetBytes(RequestBody), new TestCaseHttpResponse(), endpoint.Directory);
157+
responseBody = Encoding.UTF8.GetString(responseBodyBytes);
158+
}
159+
string message;
160+
if (Evaluate(matcher_and_creator.Item1.ToString(), matcher_and_creator.Item2.ToString(), responseBody, out message))
161+
{
162+
retval.SetSuccess();
163+
} else
164+
{
165+
retval.SetFailure(message);
166+
}
107167
}
108168
}
109169
else
110170
{
111-
retval.Message = "Endpoint has no match for request";
112-
retval.Error = true;
171+
retval.SetFailure("Endpoint has not match for request");
113172
}
114173
}
115174
}
116175
catch (Exception exception)
117176
{
118177
if (!handleErrors) throw;
119-
retval.Exception = exception;
120-
retval.Error = true;
178+
retval.SetException(exception);
121179
}
122180
return retval;
123181
}
124182
}
125183

126184
public class NetmockeryTestCaseResult
127185
{
128-
public bool OK;
129-
public bool Error;
130-
public string Message;
131-
public Exception Exception;
186+
private bool _ok;
187+
private Exception _exception;
188+
private string _message;
189+
190+
public bool OK => _ok;
191+
public bool Error => !_ok;
192+
public Exception Exception => _exception;
193+
public string Message => _message;
132194
public NetmockeryTestCase TestCase;
133195

196+
public void SetSuccess()
197+
{
198+
_ok = true;
199+
}
200+
201+
public void SetFailure(string message)
202+
{
203+
_ok = false;
204+
_message = message;
205+
}
206+
207+
public void SetException(Exception e)
208+
{
209+
Debug.Assert(e != null);
210+
SetFailure("Exception");
211+
_exception = e;
212+
}
213+
214+
private static string indent(string s)
215+
{
216+
Debug.Assert(s != null);
217+
return " " + s.Replace(Environment.NewLine, Environment.NewLine + " ");
218+
}
219+
134220
public string ResultAsString
135221
{
136222
get
@@ -149,12 +235,19 @@ public string ResultAsString
149235
shortstatus = "Error";
150236
}
151237

152-
var retval = $"{shortstatus}\n{Message}";
153-
if (Exception != null)
238+
if (Error)
239+
{
240+
var retval = $"{shortstatus}\n{indent(Message ?? "")}";
241+
if (Exception != null)
242+
{
243+
retval += "\n" + indent(Exception.ToString());
244+
}
245+
return retval;
246+
}
247+
else
154248
{
155-
retval += "\n" + Exception.ToString();
249+
return shortstatus;
156250
}
157-
return retval;
158251
}
159252
}
160253
}

netmockery/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public static void Test(string[] commandArgs)
8888
var errors = 0;
8989
foreach (var test in testDefinitions.Tests)
9090
{
91-
Write(test.Name.PadRight(40));
91+
Write(test.Name.PadRight(60));
9292
var result = test.ExecuteAsync(EndpointCollection).Result;
9393
WriteLine(result.ResultAsString);
9494
if (result.Error)

0 commit comments

Comments
 (0)