Skip to content

Commit d7db3aa

Browse files
committed
Add tests: xUnit integration tests and HTTP sample files
1 parent a8450c0 commit d7db3aa

8 files changed

Lines changed: 209 additions & 0 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<IsPackable>false</IsPackable>
5+
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
6+
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<PackageReference Include="Foundatio.Xunit.v3" Version="13.0.0" />
10+
<PackageReference Include="GitHubActionsTestLogger" Version="3.0.3" PrivateAssets="All" />
11+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.7" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
13+
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.6.2" />
14+
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.2" />
15+
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" PrivateAssets="All" />
16+
</ItemGroup>
17+
<ItemGroup>
18+
<ProjectReference Include="..\..\src\Foundatio.Skeleton.Web\Foundatio.Skeleton.Web.csproj" />
19+
</ItemGroup>
20+
</Project>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Foundatio.Messaging;
2+
using Microsoft.AspNetCore.Mvc.Testing;
3+
using Xunit;
4+
5+
namespace Foundatio.Skeleton.Tests;
6+
7+
public class MessageBusTests : IClassFixture<WebApplicationFactory<Program>>
8+
{
9+
private readonly WebApplicationFactory<Program> _factory;
10+
11+
public MessageBusTests(WebApplicationFactory<Program> factory) => _factory = factory;
12+
13+
[Fact]
14+
public async Task PublishAsync_WithSubscriber_DeliversMessageToSubscriber()
15+
{
16+
// Arrange
17+
using var scope = _factory.Services.CreateScope();
18+
var messageBus = scope.ServiceProvider.GetRequiredService<IMessageBus>();
19+
var tcs = new TaskCompletionSource<TestMessage>();
20+
var expected = new TestMessage("hello", 42);
21+
22+
await messageBus.SubscribeAsync<TestMessage>(msg =>
23+
{
24+
tcs.TrySetResult(msg);
25+
}, TestContext.Current.CancellationToken);
26+
27+
// Act
28+
await messageBus.PublishAsync(expected, cancellationToken: TestContext.Current.CancellationToken);
29+
var received = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
30+
31+
// Assert
32+
Assert.Equal(expected.Text, received.Text);
33+
Assert.Equal(expected.Number, received.Number);
34+
}
35+
36+
public record TestMessage(string Text, int Number);
37+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System.Net;
2+
using Microsoft.AspNetCore.Mvc.Testing;
3+
using Xunit;
4+
5+
namespace Foundatio.Skeleton.Tests;
6+
7+
public class StatusEndpointTests : IClassFixture<WebApplicationFactory<Program>>
8+
{
9+
private readonly WebApplicationFactory<Program> _factory;
10+
11+
public StatusEndpointTests(WebApplicationFactory<Program> factory) => _factory = factory;
12+
13+
[Fact]
14+
public async Task GetHealth_WhenCalled_ReturnsOk()
15+
{
16+
// Arrange
17+
var client = _factory.CreateClient();
18+
19+
// Act
20+
var response = await client.GetAsync("/health", TestContext.Current.CancellationToken);
21+
22+
// Assert
23+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
24+
}
25+
26+
[Fact]
27+
public async Task GetStatus_WhenCalled_ReturnsOkWithVersionAndStatus()
28+
{
29+
// Arrange
30+
var client = _factory.CreateClient();
31+
32+
// Act
33+
var response = await client.GetAsync("/api/status", TestContext.Current.CancellationToken);
34+
var content = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
35+
36+
// Assert
37+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
38+
Assert.Contains("ok", content, StringComparison.OrdinalIgnoreCase);
39+
Assert.Contains("version", content, StringComparison.OrdinalIgnoreCase);
40+
}
41+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Net;
2+
using Microsoft.AspNetCore.Mvc.Testing;
3+
using Xunit;
4+
5+
namespace Foundatio.Skeleton.Tests;
6+
7+
public class UserEndpointTests : IClassFixture<WebApplicationFactory<Program>>
8+
{
9+
private readonly HttpClient _client;
10+
11+
public UserEndpointTests(WebApplicationFactory<Program> factory) => _client = factory.CreateClient();
12+
13+
[Fact]
14+
public async Task PostUser_WithValidData_ReturnsCreatedAndGetReturnsUser()
15+
{
16+
// Arrange
17+
var request = new { FullName = "Test User", EmailAddress = "test@localhost" };
18+
19+
// Act
20+
var response = await _client.PostAsJsonAsync("/api/users", request, TestContext.Current.CancellationToken);
21+
var user = await response.Content.ReadFromJsonAsync<UserResponse>(TestContext.Current.CancellationToken);
22+
23+
// Assert
24+
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
25+
Assert.NotNull(user);
26+
Assert.Equal("Test User", user.FullName);
27+
28+
var getResponse = await _client.GetAsync($"/api/users/{user.Id}", TestContext.Current.CancellationToken);
29+
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
30+
}
31+
32+
[Fact]
33+
public async Task GetUser_WithNonExistentId_ReturnsNotFound()
34+
{
35+
// Arrange
36+
var nonExistentId = "nonexistent-id";
37+
38+
// Act
39+
var response = await _client.GetAsync($"/api/users/{nonExistentId}", TestContext.Current.CancellationToken);
40+
41+
// Assert
42+
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
43+
}
44+
45+
private record UserResponse(string Id, string FullName, string EmailAddress);
46+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Warning"
5+
}
6+
}
7+
}

tests/http/organizations.http

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@host = http://localhost:5000
2+
3+
### List all organizations
4+
GET {{host}}/api/organizations
5+
6+
### Create an organization
7+
# @name createOrganization
8+
POST {{host}}/api/organizations
9+
Content-Type: application/json
10+
11+
{
12+
"name": "Test Organization"
13+
}
14+
15+
### Get an organization by id
16+
GET {{host}}/api/organizations/{{createOrganization.response.body.id}}
17+
18+
### Delete an organization
19+
DELETE {{host}}/api/organizations/{{createOrganization.response.body.id}}

tests/http/status.http

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@host = http://localhost:5000
2+
3+
### Health check
4+
GET {{host}}/health
5+
6+
### Status
7+
GET {{host}}/api/status
8+
9+
### Prometheus metrics
10+
GET {{host}}/metrics

tests/http/users.http

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@host = http://localhost:5000
2+
3+
### List all users
4+
GET {{host}}/api/users
5+
6+
### Create a user
7+
# @name createUser
8+
POST {{host}}/api/users
9+
Content-Type: application/json
10+
11+
{
12+
"fullName": "Test User",
13+
"emailAddress": "test@localhost"
14+
}
15+
16+
### Get a user by id
17+
GET {{host}}/api/users/{{createUser.response.body.id}}
18+
19+
### Update a user
20+
PUT {{host}}/api/users/{{createUser.response.body.id}}
21+
Content-Type: application/json
22+
23+
{
24+
"fullName": "Updated User",
25+
"emailAddress": "updated@localhost"
26+
}
27+
28+
### Delete a user
29+
DELETE {{host}}/api/users/{{createUser.response.body.id}}

0 commit comments

Comments
 (0)