Skip to content

Commit 4cc00b0

Browse files
committed
add router tests for GET requests
1 parent 62fefff commit 4cc00b0

File tree

10 files changed

+165
-33
lines changed

10 files changed

+165
-33
lines changed
Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
1-
using System;
2-
using JsonApiDotNetCore.Abstractions;
1+
using JsonApiDotNetCore.Abstractions;
32
using JsonApiDotNetCore.Data;
43

54
namespace JsonApiDotNetCore.Controllers
65
{
7-
public class ControllerBuilder
6+
public class ControllerBuilder : IControllerBuilder
87
{
9-
private readonly JsonApiContext _context;
10-
11-
public ControllerBuilder(JsonApiContext context)
12-
{
13-
_context = context;
14-
}
15-
16-
public JsonApiController BuildController()
8+
public IJsonApiController BuildController(JsonApiContext context)
179
{
18-
return new JsonApiController(_context, new ResourceRepository(_context));
10+
return new JsonApiController(context, new ResourceRepository(context));
1911
}
2012
}
2113
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using JsonApiDotNetCore.Abstractions;
2+
3+
namespace JsonApiDotNetCore.Controllers
4+
{
5+
public interface IControllerBuilder
6+
{
7+
IJsonApiController BuildController(JsonApiContext context);
8+
}
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using System.Reflection;
3+
using System.Collections.Generic;
4+
5+
namespace JsonApiDotNetCore.Controllers
6+
{
7+
public interface IJsonApiController
8+
{
9+
ObjectResult Get();
10+
ObjectResult Get(string id);
11+
ObjectResult Post(object entity);
12+
ObjectResult Patch(string id, Dictionary<PropertyInfo, object> entityPatch);
13+
ObjectResult Delete(string id);
14+
}
15+
}

JsonApiDotNetCore/Controllers/JsonApiController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace JsonApiDotNetCore.Controllers
88
{
9-
public class JsonApiController
9+
public class JsonApiController : IJsonApiController
1010
{
1111
protected readonly JsonApiContext JsonApiContext;
1212
private readonly ResourceRepository _resourceRepository;

JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using AutoMapper;
33
using JsonApiDotNetCore.Configuration;
4+
using JsonApiDotNetCore.Controllers;
45
using JsonApiDotNetCore.Routing;
56
using Microsoft.Extensions.DependencyInjection;
67

@@ -17,7 +18,7 @@ public static void AddJsonApi(this IServiceCollection services, Action<IJsonApiM
1718
{
1819
config.ResourceMapper = new MapperConfiguration(cfg => {}).CreateMapper();
1920
}
20-
services.AddSingleton(_ => new Router(config));
21+
services.AddSingleton(_ => new Router(config, new RouteBuilder(config), new ControllerBuilder()));
2122
}
2223
}
2324
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.AspNetCore.Http;
2+
3+
namespace JsonApiDotNetCore.Routing
4+
{
5+
public interface IRouteBuilder
6+
{
7+
Route BuildFromRequest(HttpRequest request);
8+
}
9+
}

JsonApiDotNetCore/Routing/RouteBuilder.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,30 @@
66

77
namespace JsonApiDotNetCore.Routing
88
{
9-
public class RouteBuilder
9+
public class RouteBuilder : IRouteBuilder
1010
{
1111
private RouteDefinition _baseRouteDefinition;
1212
private string _baseResourceId;
13-
private readonly HttpRequest _request;
1413
private readonly JsonApiModelConfiguration _configuration;
1514

16-
public RouteBuilder(HttpRequest request, JsonApiModelConfiguration configuration)
15+
public RouteBuilder(JsonApiModelConfiguration configuration)
1716
{
18-
_request = request;
1917
_configuration = configuration;
2018
}
2119

22-
public Route BuildFromRequest()
20+
public Route BuildFromRequest(HttpRequest request)
2321
{
24-
var remainingPathString = SetBaseRouteDefinition();
22+
var remainingPathString = SetBaseRouteDefinition(request.Path);
2523

2624
if (PathStringIsEmpty(remainingPathString))
2725
{ // {baseResource}
28-
return new Route(_baseRouteDefinition.ModelType, _request.Method, null, _baseRouteDefinition);
26+
return new Route(_baseRouteDefinition.ModelType, request.Method, null, _baseRouteDefinition);
2927
}
3028

3129
remainingPathString = SetBaseResourceId(remainingPathString);
3230
if (PathStringIsEmpty(remainingPathString))
3331
{ // {baseResource}/{baseResourceId}
34-
return new Route(_baseRouteDefinition.ModelType, _request.Method, _baseResourceId, _baseRouteDefinition);
32+
return new Route(_baseRouteDefinition.ModelType, request.Method, _baseResourceId, _baseRouteDefinition);
3533
}
3634

3735
// { baseResource}/{ baseResourceId}/{relatedResourceName}
@@ -43,20 +41,20 @@ public Route BuildFromRequest()
4341
}
4442

4543
var relationshipType = GetTypeOfRelatedResource(relatedResource);
46-
return new RelationalRoute(_baseRouteDefinition.ModelType, _request.Method, _baseResourceId, _baseRouteDefinition, relationshipType, relatedResource);
44+
return new RelationalRoute(_baseRouteDefinition.ModelType, request.Method, _baseResourceId, _baseRouteDefinition, relationshipType, relatedResource);
4745
}
4846

4947
private bool PathStringIsEmpty(PathString pathString)
5048
{
5149
return pathString.HasValue ? string.IsNullOrEmpty(pathString.ToString().TrimStart('/')) : true;
5250
}
5351

54-
private PathString SetBaseRouteDefinition()
52+
private PathString SetBaseRouteDefinition(PathString path)
5553
{
5654
foreach (var rte in _configuration.Routes)
5755
{
5856
PathString remainingPathString;
59-
if (_request.Path.StartsWithSegments(new PathString(rte.PathString), StringComparison.OrdinalIgnoreCase, out remainingPathString))
57+
if (path.StartsWithSegments(new PathString(rte.PathString), StringComparison.OrdinalIgnoreCase, out remainingPathString))
6058
{
6159
_baseRouteDefinition = rte;
6260
return remainingPathString;
@@ -76,7 +74,6 @@ private Type GetTypeOfRelatedResource(string relationshipName)
7674
return ModelAccessor.GetTypeFromModelRelationshipName(_baseRouteDefinition.ModelType, relationshipName);
7775
}
7876

79-
8077
// TODO: Why is this here?
8178
public static string BuildRoute(string nameSpace, string resourceCollectionName)
8279
{

JsonApiDotNetCore/Routing/Router.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using System;
2+
using System.Text;
23
using JsonApiDotNetCore.Abstractions;
34
using JsonApiDotNetCore.Configuration;
45
using JsonApiDotNetCore.Controllers;
56
using JsonApiDotNetCore.Services;
67
using Microsoft.AspNetCore.Http;
78
using Microsoft.AspNetCore.Mvc;
9+
using Newtonsoft.Json;
810

911
namespace JsonApiDotNetCore.Routing
1012
{
@@ -13,17 +15,21 @@ public class Router : IRouter
1315
private readonly JsonApiModelConfiguration _jsonApiModelConfiguration;
1416
private IServiceProvider _serviceProvider;
1517
private JsonApiContext _jsonApiContext;
18+
private IRouteBuilder _routeBuilder;
19+
private IControllerBuilder _controllerBuilder;
1620

17-
public Router(JsonApiModelConfiguration configuration)
21+
public Router(JsonApiModelConfiguration configuration, IRouteBuilder routeBuilder, IControllerBuilder controllerBuilder)
1822
{
1923
_jsonApiModelConfiguration = configuration;
24+
_routeBuilder = routeBuilder;
25+
_controllerBuilder = controllerBuilder;
2026
}
2127

2228
public bool HandleJsonApiRoute(HttpContext context, IServiceProvider serviceProvider)
2329
{
2430
_serviceProvider = serviceProvider;
2531

26-
var route = new RouteBuilder(context.Request, _jsonApiModelConfiguration).BuildFromRequest();
32+
var route = _routeBuilder.BuildFromRequest(context.Request);
2733
if (route == null) return false;
2834

2935
InitializeContext(context, route);
@@ -40,15 +46,16 @@ private void InitializeContext(HttpContext context, Route route)
4046

4147
private void CallController()
4248
{
43-
var controller = new ControllerBuilder(_jsonApiContext).BuildController();
49+
var controller = _controllerBuilder.BuildController(_jsonApiContext);
50+
4451
var result = ActivateControllerMethod(controller);
4552

4653
result.Value = SerializeResult(result.Value);
4754

4855
SendResponse(result);
4956
}
5057

51-
private ObjectResult ActivateControllerMethod(JsonApiController controller)
58+
private ObjectResult ActivateControllerMethod(IJsonApiController controller)
5259
{
5360
var route = _jsonApiContext.Route;
5461
switch (route.RequestMethod)
@@ -76,7 +83,7 @@ private void SendResponse(ObjectResult result)
7683
var context = _jsonApiContext.HttpContext;
7784
context.Response.StatusCode = result.StatusCode ?? 500;
7885
context.Response.ContentType = "application/vnd.api+json";
79-
context.Response.WriteAsync(result.Value == null ? "" : result.Value.ToString());
86+
context.Response.WriteAsync(result.Value == null ? "" : result.Value.ToString(), Encoding.UTF8);
8087
context.Response.Body.Flush();
8188
}
8289
}

JsonApiDotNetCoreTests/Middleware/UnitTests/JsonApiMiddlewareTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
namespace JsonApiDotNetCoreTests.Middleware.UnitTests
1010
{
11-
// see example explanation on xUnit.net website:
12-
// https://xunit.github.io/docs/getting-started-dotnet-core.html
1311
public class JsonApiMiddlewareTests
1412
{
1513
[Fact]
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System;
2+
using Microsoft.AspNetCore.Http;
3+
using Moq;
4+
using Xunit;
5+
using JsonApiDotNetCore.Abstractions;
6+
using JsonApiDotNetCore.Configuration;
7+
using JsonApiDotNetCore.Routing;
8+
using JsonApiDotNetCore.Controllers;
9+
using Microsoft.AspNetCore.Mvc;
10+
using System.Text;
11+
using System.Threading;
12+
using System.Threading.Tasks;
13+
using Microsoft.AspNetCore.Http.Internal;
14+
using System.IO;
15+
16+
namespace JsonApiDotNetCoreTests.Routing.UnitTests
17+
{
18+
public class RouterTests
19+
{
20+
[Fact]
21+
public void HandleJsonApiRoute_ReturnsFalse_IfTheRouteCannotBeBuilt()
22+
{
23+
//--> arrange
24+
var httpContextMock = new Mock<HttpContext>();
25+
httpContextMock.SetupAllProperties();
26+
27+
// since this is an empty stub, IRouteBuilder.BuildFromRequest() will always return null
28+
var routeBuilderMock = new Mock<IRouteBuilder>();
29+
30+
var router = new Router(null, routeBuilderMock.Object, null);
31+
32+
//--> act
33+
var result = router.HandleJsonApiRoute(httpContextMock.Object, null);
34+
35+
//--> assert
36+
Assert.False(result);
37+
}
38+
39+
[Fact]
40+
public void HandleJsonApiRoute_CallsGetMethod_ForGetRequest()
41+
{
42+
//--> arrange
43+
var httpContextMock = new Mock<HttpContext>();
44+
httpContextMock.SetupAllProperties();
45+
var httpResponseMock = new Mock<HttpResponse>();
46+
httpResponseMock.Setup(r => r.Body).Returns(new MemoryStream());
47+
httpContextMock.Setup(c => c.Response).Returns(httpResponseMock.Object);
48+
49+
var route = new Route(null, "GET", null, null);
50+
51+
var routeBuilderMock = new Mock<IRouteBuilder>();
52+
routeBuilderMock.Setup(rb => rb.BuildFromRequest(null)).Returns(route);
53+
54+
var serviceProviderMock = new Mock<IServiceProvider>();
55+
56+
var controllerMock = new Mock<IJsonApiController>();
57+
controllerMock.Setup(c => c.Get()).Returns(new OkObjectResult(null));
58+
var controllerBuilder = new Mock<IControllerBuilder>();
59+
controllerBuilder.Setup(cb => cb.BuildController(It.IsAny<JsonApiContext>())).Returns(controllerMock.Object);
60+
61+
var router = new Router(new JsonApiModelConfiguration(), routeBuilderMock.Object, controllerBuilder.Object);
62+
63+
//--> act
64+
var result = router.HandleJsonApiRoute(httpContextMock.Object, serviceProviderMock.Object);
65+
66+
//--> assert
67+
Assert.True(result);
68+
controllerMock.Verify(c => c.Get());
69+
}
70+
71+
[Fact]
72+
public void HandleJsonApiRoute_CallsGetIdMethod_ForGetIdRequest()
73+
{
74+
//--> arrange
75+
const string resourceId = "1";
76+
var httpContextMock = new Mock<HttpContext>();
77+
httpContextMock.SetupAllProperties();
78+
var httpResponseMock = new Mock<HttpResponse>();
79+
httpResponseMock.Setup(r => r.Body).Returns(new MemoryStream());
80+
httpContextMock.Setup(c => c.Response).Returns(httpResponseMock.Object);
81+
82+
var route = new Route(null, "GET", resourceId, null);
83+
84+
var routeBuilderMock = new Mock<IRouteBuilder>();
85+
routeBuilderMock.Setup(rb => rb.BuildFromRequest(null)).Returns(route);
86+
87+
var serviceProviderMock = new Mock<IServiceProvider>();
88+
89+
var controllerMock = new Mock<IJsonApiController>();
90+
controllerMock.Setup(c => c.Get(resourceId)).Returns(new OkObjectResult(null));
91+
var controllerBuilder = new Mock<IControllerBuilder>();
92+
controllerBuilder.Setup(cb => cb.BuildController(It.IsAny<JsonApiContext>())).Returns(controllerMock.Object);
93+
94+
var router = new Router(new JsonApiModelConfiguration(), routeBuilderMock.Object, controllerBuilder.Object);
95+
96+
//--> act
97+
var result = router.HandleJsonApiRoute(httpContextMock.Object, serviceProviderMock.Object);
98+
99+
//--> assert
100+
Assert.True(result);
101+
controllerMock.Verify(c => c.Get(resourceId));
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)