Skip to content

Commit 52bcefd

Browse files
committed
Started implementation of test framework
Includes refactoring from concrete HttpResponse/Request to I...Wrapper's
1 parent 3a29cf2 commit 52bcefd

File tree

7 files changed

+384
-4
lines changed

7 files changed

+384
-4
lines changed

UnitTests/TestTestCommand.cs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Xunit;
6+
using netmockery;
7+
8+
namespace UnitTests
9+
{
10+
public static class TESTCOMMAND_CONSTANTS
11+
{
12+
public const string ENDPOINTJSON = @"
13+
{
14+
'name': 'foo',
15+
'pathregex': '^/foo/$',
16+
'responses': [
17+
{
18+
'match': {'regex': 'test'},
19+
'response': {
20+
'file': 'content.txt',
21+
'contenttype': 'text/plain'
22+
}
23+
},
24+
{
25+
'match': {},
26+
'response': {
27+
'script': 'myscript.csscript',
28+
'contenttype': 'text/xml',
29+
'replacements': [
30+
{'search': 'a', 'replace': 'b'},
31+
{'search': 'foo', 'replace': 'bar'}
32+
]
33+
}
34+
}
35+
]
36+
}
37+
";
38+
39+
public const string TESTS = @"
40+
[
41+
{
42+
'name': '/foo/ request works',
43+
'requestpath': '/foo/',
44+
'requestbody': 'heisann test',
45+
'expectedresponsebody': 'FOOBARBOOBAR'
46+
}
47+
]
48+
";
49+
50+
}
51+
52+
public class TestTestCommandWithoutTestsuite : IDisposable
53+
{
54+
DirectoryCreator dc;
55+
public TestTestCommandWithoutTestsuite()
56+
{
57+
dc = new DirectoryCreator();
58+
dc.AddFile("endpoint1\\endpoint.json", TESTCOMMAND_CONSTANTS.ENDPOINTJSON);
59+
}
60+
61+
public void Dispose()
62+
{
63+
dc.Dispose();
64+
}
65+
66+
[Fact]
67+
public void CheckIfTestSuiteExists()
68+
{
69+
Assert.False(EndpointTestDefinition.HasTestSuite(dc.DirectoryName));
70+
}
71+
72+
[Fact]
73+
public void WorksIfEndpointNamedTest()
74+
{
75+
dc.AddFile("tests\\endpoint.json", TESTCOMMAND_CONSTANTS.ENDPOINTJSON);
76+
Assert.False(EndpointTestDefinition.HasTestSuite(dc.DirectoryName));
77+
}
78+
}
79+
80+
81+
public class TestTestCommand : IDisposable
82+
{
83+
DirectoryCreator dc;
84+
public TestTestCommand()
85+
{
86+
dc = new DirectoryCreator();
87+
dc.AddFile("endpoint1\\endpoint.json", TESTCOMMAND_CONSTANTS.ENDPOINTJSON);
88+
dc.AddFile("endpoint1\\content.txt", "FOOBARBOOBAR");
89+
dc.AddFile("tests\\tests.json", TESTCOMMAND_CONSTANTS.TESTS);
90+
}
91+
92+
public void Dispose()
93+
{
94+
dc.Dispose();
95+
}
96+
97+
[Fact]
98+
public void DetectsTestSuite()
99+
{
100+
Assert.True(EndpointTestDefinition.HasTestSuite(dc.DirectoryName));
101+
102+
}
103+
104+
[Fact]
105+
public void CanReadTestsFromJSONFile()
106+
{
107+
var endpointTestDefinition = EndpointTestDefinition.ReadFromDirectory(dc.DirectoryName);
108+
Assert.Equal(1, endpointTestDefinition.Tests.Count());
109+
var test = endpointTestDefinition.Tests.ElementAt(0);
110+
Assert.Equal("/foo/ request works", test.Name);
111+
Assert.Equal("/foo/", test.RequestPath);
112+
Assert.Equal("heisann test", test.RequestBody);
113+
Assert.Equal("FOOBARBOOBAR", test.ExpectedResponseBody);
114+
}
115+
116+
[Fact]
117+
async public void CanExecuteTest()
118+
{
119+
var endpointTestDefinition = EndpointTestDefinition.ReadFromDirectory(dc.DirectoryName);
120+
var test = endpointTestDefinition.Tests.ElementAt(0);
121+
122+
var result = await test.ExecuteAsync(EndpointCollectionReader.ReadFromDirectory(dc.DirectoryName), handleErrors: false);
123+
Assert.True(result.OK);
124+
}
125+
}
126+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Newtonsoft.Json;
7+
8+
namespace netmockery
9+
{
10+
public class EndpointTestDefinition
11+
{
12+
private NetmockeryTestCase[] testcases;
13+
public EndpointTestDefinition(IEnumerable<NetmockeryTestCase> testcases)
14+
{
15+
this.testcases = testcases.ToArray();
16+
}
17+
18+
public IEnumerable<NetmockeryTestCase> Tests => testcases;
19+
20+
static public bool HasTestSuite(string directory)
21+
{
22+
return File.Exists(tests_json_filename(directory));
23+
}
24+
25+
static private string tests_json_filename(string directory) => Path.Combine(directory, "tests", "tests.json");
26+
27+
public static EndpointTestDefinition ReadFromDirectory(string directory)
28+
{
29+
var jsonTests = JsonConvert.DeserializeObject<List<JSONTest>>(File.ReadAllText(tests_json_filename(directory)));
30+
return new EndpointTestDefinition(from jsontest in jsonTests select jsontest.CreateTestCase());
31+
}
32+
}
33+
}

netmockery/ForwardResponseCreator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public override string ToString()
3636

3737
string[] HEADERS_TO_SKIP = new[] { "connection", "content-length", "content-type", "accept-encoding", "expect", "host" };
3838

39-
public override async Task<byte[]> CreateResponseAsync(HttpRequest request, byte[] body, HttpResponse response, string endpointDirectory)
39+
public override async Task<byte[]> CreateResponseAsync(IHttpRequestWrapper request, byte[] body, IHttpResponseWrapper response, string endpointDirectory)
4040
{
4141
var requestPath = request.Path.ToString();
4242
if (StripPath != null)

netmockery/JSONReader.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,28 @@ public static Endpoint ReadEndpoint(string jsonString, string rootDir)
1616
}
1717
}
1818

19+
public class JSONTest
20+
{
21+
/*
22+
{
23+
'name': '/foo/ request works',
24+
'requestpath': '/foo/',
25+
'requestbody': 'heisann test',
26+
'expectedresponsebody': 'FOOBARBOOBAR'
27+
}
28+
29+
*/
30+
public string name;
31+
public string requestpath;
32+
public string requestbody;
33+
public string expectedresponsebody;
34+
35+
public NetmockeryTestCase CreateTestCase()
36+
{
37+
return new NetmockeryTestCase { Name = name, RequestPath = requestpath, RequestBody = requestbody, ExpectedResponseBody = expectedresponsebody };
38+
}
39+
}
40+
1941
public class JSONResponse
2042
{
2143
public JSONRequestMatcher match;

netmockery/NetmockeryTestCase.cs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using Microsoft.AspNetCore.Http;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using System.IO;
9+
10+
namespace netmockery
11+
{
12+
public class TestCaseHttpRequest : IHttpRequestWrapper
13+
{
14+
private string path;
15+
private HeaderDictionary headerDictionary;
16+
17+
public TestCaseHttpRequest(string path)
18+
{
19+
this.path = path;
20+
}
21+
22+
public IHeaderDictionary Headers
23+
{
24+
get
25+
{
26+
return headerDictionary;
27+
}
28+
}
29+
30+
public PathString Path
31+
{
32+
get
33+
{
34+
35+
return new PathString(path);
36+
}
37+
}
38+
}
39+
40+
public class TestCaseHttpResponse : IHttpResponseWrapper
41+
{
42+
MemoryStream memoryStream = new MemoryStream();
43+
string writtenContent;
44+
Encoding writtenEncoding;
45+
string contentType;
46+
47+
public Stream Body
48+
{
49+
get
50+
{
51+
return memoryStream;
52+
}
53+
}
54+
55+
public string ContentType
56+
{
57+
set
58+
{
59+
contentType = value;
60+
}
61+
}
62+
63+
async public Task WriteAsync(string content, Encoding encoding)
64+
{
65+
66+
writtenContent = content;
67+
writtenEncoding = encoding;
68+
await Task.Yield();
69+
}
70+
}
71+
public class NetmockeryTestCase
72+
{
73+
public string Name;
74+
public string RequestPath;
75+
public string RequestBody;
76+
public string ExpectedResponseBody;
77+
78+
async public Task<NetmockeryTestCaseResult> ExecuteAsync(EndpointCollection endpointCollection, bool handleErrors=true)
79+
{
80+
Debug.Assert(endpointCollection != null);
81+
82+
var retval = new NetmockeryTestCaseResult { TestCase = this };
83+
try
84+
{
85+
var endpoint = endpointCollection.Resolve(RequestPath);
86+
if (endpoint == null)
87+
{
88+
retval.Message = "No endpoint matches request path";
89+
retval.Error = true;
90+
}
91+
else
92+
{
93+
bool singleMatch;
94+
var matcher_and_creator = endpoint.Resolve(new PathString(RequestPath), RequestBody, null, out singleMatch);
95+
if (matcher_and_creator != null)
96+
{
97+
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+
else
105+
{
106+
retval.Message = "Endpoint has no match for request";
107+
retval.Error = true;
108+
}
109+
}
110+
}
111+
catch (Exception exception)
112+
{
113+
if (!handleErrors) throw;
114+
retval.Exception = exception;
115+
retval.Error = true;
116+
}
117+
return retval;
118+
}
119+
}
120+
121+
public class NetmockeryTestCaseResult
122+
{
123+
public bool OK;
124+
public bool Error;
125+
public string Message;
126+
public Exception Exception;
127+
public NetmockeryTestCase TestCase;
128+
}
129+
}

0 commit comments

Comments
 (0)