Skip to content

Commit 2b1aab7

Browse files
Updated unit testing docs for new library (#46)
1 parent ca982a9 commit 2b1aab7

File tree

3 files changed

+130
-12
lines changed

3 files changed

+130
-12
lines changed

docs/development/debugging.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ sidebar_position: 0
99

1010
GraphQL will execute sibling fields asynchronously during normal operation. This includes multiple top-level controller action calls. However, during a debugging session, having multiple fields trying to resolve themselves can play havoc with your debug cursor. If you've ever encountered a situation where the yellow line in Visual Studio seemly jumps around to random lines of code then you've experienced this issue.
1111

12-
At startup, it can help to disable asynchronous field resolution and instead force each field to execute in sequential order awaiting its completion before beginning the next one. Don't forget to disable this in production though, as awaiting fields individually will _**significantly**_ impact performance.
12+
At startup, it can help to disable asynchronous field resolution and instead force each field to execute in sequential order awaiting its completion before beginning the next one.
1313

1414
```csharp title="Configure Debug Mode"
1515
services.AddGraphQL(options =>
@@ -18,3 +18,6 @@ services.AddGraphQL(options =>
1818
options.ExecutionOptions.DebugMode = true;
1919
});
2020
```
21+
:::danger Performance Killer
22+
Don't forget to disable debug mode in production though. Awaiting fields individually will _**significantly**_ impact performance.
23+
:::

docs/development/unit-testing.md

Lines changed: 124 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,73 @@ sidebar_label: Unit Testing
55
sidebar_position: 1
66
---
77

8-
GraphQL ASP.NET has more than `3500 unit tests and 91% code coverage`. Much of this is powered by a test component designed to quickly build a configurable, fully mocked server instance to perform a query. It may be helpful to download the code and extend it for harnessing your own controllers.
8+
<span className="pill">.NET 6+</span>
9+
<br/>
10+
<br/>
911

10-
The `TestServerBuilder<TSchema>` can be found in the `graphql-aspnet-testframework` project of the primary repo and is dependent on `Moq`. As its part of the core library solution you'll want to remove the project reference to `graphql-aspnet` project and instead add a reference to the nuget package.
12+
:::info
13+
Your test projects must target .NET 6 or greater to use the test framework
14+
:::
15+
16+
GraphQL ASP.NET has more than `3500 unit tests and 91% code coverage`. All the internal integration tests are powered by a framework designed to quickly build a configurable, fully mocked server instance to perform a query against the runtime. It may be helpful to use and extend the framework to test your own controllers.
1117

1218
This document explains how to perform some common test functions for your own controller methods.
1319

20+
21+
## Install the Framework
22+
23+
Add a reference to the [Nuget Package](https://www.nuget.org/packages/GraphQL.AspNet.TestFramework) `GraphQL.AspNet.TestFramework` to your unit test project. The framework is just a class library and not dependent on any individual testing framework like NUnit or XUnit. However, it does mock some runtime only objects and, as a result, is dependent on [Moq](https://www.nuget.org/packages/Moq).
24+
25+
```powershell title="Install the Test Framework"
26+
# Using the dotnet CLI
27+
> dotnet add package GraphQL.AspNet.TestFramework
28+
29+
# Using Package Manager Console
30+
> Install-Package GraphQL.AspNet.TestFramework
31+
```
32+
33+
34+
1435
## Create a Test Server
1536

16-
1. Create a new instance of the `TestServerBuilder`. The builder takes in a set of flags to perform some auto configurations for common scenarios such as exposing exceptions or altering the casing of graph type names.
37+
1. Create a new instance of the `TestServerBuilder`. The builder takes in an optional set of flags to perform some auto configurations for common scenarios such as exposing exceptions or altering the casing of graph type names.
1738
2. Configure your test scenario
1839

1940
- Use `.User` to add any permissions to the mocked user account
2041
- Use `.Authorization` to add any security policy definitions if you wish to test security
2142
- Use `.AddGraphQL()` to mimic the functionality of schema configuration used when your application starts.
22-
- The `TestServerBuilder` implements `IServiceCollection`, add any additional mocked services as needed to ensure your controllers are wired up correctly by the runtime.
43+
- `TestServerBuilder` implements `IServiceCollection`. Add any additional mocked services as needed to ensure your controllers are wired up correctly by the runtime.
2344

2445
3. Build the server instance using `.Build()`
2546

2647
```csharp title="Configuring a Test Server Instance"
2748
[Test]
2849
public async Task MyController_InvocationTest()
2950
{
51+
// Arrange
3052
var builder = new TestServerBuilder();
3153
builder.AddGraphQL(o => {
3254
o.AddController<MyController>();
3355
});
3456

57+
// Act
3558
var server = builder.Build();
36-
//...
59+
60+
// continued...
3761
}
3862

3963
```
4064

65+
:::tip Custom Schemas
66+
Use `TestServerBuild<TSchema>` to test against a custom defined schema instance.
67+
:::
68+
4169
## Execute a Query
4270

43-
1. Mock the query execution context (the object that the runtime acts on) using `.CreateQueryContextBuilder()`
44-
2. Configure the text, variables etc. on the builder.
71+
Follow these steps to execute a query against the runtime. If your controller is registered to the test server and the appropriate field is requested in the query, it will be invoked.
72+
73+
1. Create a builder to generate a mocked execution context (the object that the runtime acts on) using `.CreateQueryContextBuilder()`
74+
2. Configure the query text, variables etc. on the builder.
4575
3. Build the context and submit it for processing:
4676
- Use `server.ExecuteQuery()` to process the context. `context.Result` will be filled with the final `IQueryExecutionResult` which can be inspected for resultant data fields and error messages.
4777
- Use `server.RenderResult()` to generate the json string a client would recieve if they performed the query.
@@ -50,13 +80,20 @@ public async Task MyController_InvocationTest()
5080
```csharp title="Executing a Test Query"
5181
[Test]
5282
public async Task MyController_InvocationTest()
53-
{
54-
// ...
83+
{
84+
// Arrange
85+
var builder = new TestServerBuilder();
86+
builder.AddGraphQL(o => {
87+
o.AddController<MyController>();
88+
});
89+
5590
var server = builder.Build();
5691
var contextBuilder = server.CreateQueryContextBuilder();
5792
contextBuilder.AddQueryText("query { controller { actionMethod { property1 } } }");
5893

5994
var context = contextBuilder.Build();
95+
96+
// Act
6097
var result = await server.RenderResult(context);
6198

6299
/* result contains the string for:
@@ -71,5 +108,83 @@ public async Task MyController_InvocationTest()
71108
}
72109
*/
73110
}
111+
```
112+
113+
## Other Test Scenarios
114+
115+
### Throwing Exceptions
116+
If you need to test that your controller throws an appropriate exception you can inspect the response object (instead of rendering a result). The exception will be attached to an error message generated during the query execution.
117+
118+
```csharp title="Testing for Thrown Exceptions"
119+
[Test]
120+
public async Task MyController_InvocationTest()
121+
{
122+
// Arrange
123+
var builder = new TestServerBuilder();
124+
builder.AddGraphQL(o => {
125+
o.AddController<MyController>();
126+
});
127+
128+
var server = builder.Build();
129+
var contextBuilder = server.CreateQueryContextBuilder();
130+
contextBuilder.AddQueryText("query { controller { actionMethod { property1 } } }");
131+
132+
var context = contextBuilder.Build();
133+
134+
// Act
135+
// Use ExecuteQuery instead of RenderResult to obtain the response object
136+
// highlight-next-line
137+
var result = await server.ExecuteQuery(queryBuilder);
138+
139+
// Assert
140+
// ensure a message was captured
141+
Assert.IsNotNull(result);
142+
Assert.AreEqual(1, result.Messages.Count);
143+
Assert.IsInstanceOf(typeof(MyException), result.Messages[0].Exception);
144+
}
145+
```
146+
147+
:::tip
148+
Use `server.ExecuteQuery` to obtain a reference to the response object. This allows you to interrogate the message data before its rendered as a json document.
149+
:::
150+
151+
152+
### Authn & Authz
153+
154+
Test authentication and authorization scenarios by configuring both the policies the server should support and the claims or roles the user will present during the test.
155+
156+
```csharp
157+
[Test]
158+
public async Task WhenUserHasPolicy_ThenAllowExecution()
159+
{
160+
// Arrange
161+
var builder = new TestServerBuilder();
162+
builder.AddGraphQL(o => {
163+
o.AddController<MyController>();
164+
});
74165

166+
// configure the policies the server will recognize
167+
// and the claims the user context will have.
168+
// This specific test assumes that the controller method
169+
// defines an authorization requirement of "policy1".
170+
// highlight-start
171+
builder.Authorization.AddClaimPolicy("policy1", "myClaimType", "myClaimValue");
172+
builder.UserContext.AddUserClaim("myClaimType", "myClaimValue")
173+
// highlight-end
174+
175+
var server = builder.Build();
176+
var contextBuilder = server.CreateQueryContextBuilder();
177+
contextBuilder.AddQueryText("query { controller { actionMethod { property1 } } }");
178+
179+
var context = contextBuilder.Build();
180+
181+
// Act
182+
var result = await server.RenderResult(queryBuilder);
183+
184+
// Assert
185+
// ....
186+
}
75187
```
188+
189+
The user context is always injected when you run a query on the test server. By default it is an anonymous user and credentials are applied when you add a claim or policy to the context during setup.
190+

docs/server-extensions/multipart-requests.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ A bitwise flag enumeration allowing the inclusion of different types of values f
448448
mpOptions.RequestMode = MultipartRequestMode.Default;
449449
```
450450

451-
A bitwise flag enumeration that controls which actions the multi-part request extension. By default, both batch queries and file uploads are enabled.
451+
A bitwise flag enumeration that controls which parts of the multi-part request extension are enabled. By default, both batch queries and file uploads are enabled.
452452

453453
| Option | Description |
454454
| ------------- | ----------------- |
@@ -508,7 +508,7 @@ mpOptions.RequireMultipartRequestHttpProcessor = true;
508508
| ------------- | ----------------- |
509509
| `true` | `true`, `false` |
510510

511-
Determines if, when starting up the application, the extension will check that the required http processor is registered. When set to true, if the required processor is not registered and configuration exception will be thrown and the server will fail to start. This can be helpful when registering multiple extensions to ensure that a valid processor is registered such that multipart form requests will be handled correctly.
511+
Determines if, when starting up the application, the extension will check that the required http processor is registered. When set to true, if the required processor is not registered a configuration exception will be thrown and the server will fail to start. This can be helpful when registering multiple extensions to ensure that a valid processor is registered such that multipart-form requests will be handled correctly.
512512

513513
## Demo Project
514514
See the [demo projects](../reference/demo-projects.md) for a sample project utilizing [jaydenseric's apollo-upload-client](https://github.com/jaydenseric/apollo-upload-client) as a front end for performing file uploads against this extension.

0 commit comments

Comments
 (0)