Skip to content

Commit

Permalink
tests: use web application factory's DI service provider in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
undrcrxwn committed Feb 16, 2024
1 parent 200b4c4 commit 8123416
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CrowdParlay.Social.Api;
using CrowdParlay.Social.IntegrationTests.Services;
using MassTransit.Testing;
using Microsoft.Extensions.DependencyInjection;
using Nito.AsyncEx;
using Testcontainers.Neo4j;

Expand All @@ -9,7 +9,7 @@ namespace CrowdParlay.Social.IntegrationTests.Fixtures;
public class WebApplicationContext
{
public readonly HttpClient Client;
public readonly ITestHarness Harness;
public readonly IServiceProvider Services;

public WebApplicationContext()
{
Expand All @@ -20,7 +20,7 @@ public WebApplicationContext()
.Build();

AsyncContext.Run(async () => await neo4j.StartAsync());

// ReSharper disable once InconsistentNaming
var neo4jConfiguration = new Neo4jConfiguration(
Uri: neo4j.GetConnectionString(),
Expand All @@ -29,6 +29,6 @@ public WebApplicationContext()

var webApplicationFactory = new TestWebApplicationFactory<Program>(neo4jConfiguration);
Client = webApplicationFactory.CreateClient();
Harness = webApplicationFactory.Services.GetTestHarness();
Services = webApplicationFactory.Services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace CrowdParlay.Social.IntegrationTests.Services;

public static class Authorization
{
public static string ProduceAccessToken(string userId) => new JwtBuilder()
public static string ProduceAccessToken(Guid userId) => new JwtBuilder()
.WithAlgorithm(new HMACSHA256Algorithm())
.WithSecret(string.Empty)
.AddClaim("sub", userId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,41 @@
using System.Net;
using System.Net.Http.Json;
using CrowdParlay.Communication;
using CrowdParlay.Social.Application.Abstractions;
using CrowdParlay.Social.Application.DTOs;
using CrowdParlay.Social.IntegrationTests.Fixtures;
using FluentAssertions;
using MassTransit.Testing;
using Microsoft.Extensions.DependencyInjection;

namespace CrowdParlay.Social.IntegrationTests.Tests;

public class AuthorsControllerTests : IClassFixture<WebApplicationContext>
{
private readonly HttpClient _client;
private readonly ITestHarness _harness;
private readonly IServiceProvider _services;

public AuthorsControllerTests(WebApplicationContext context)
{
_client = context.Client;
_harness = context.Harness;
_services = context.Services;
}

[Fact(DisplayName = "User created event creates author")]
public async Task CreateAuthor_Positive()
[Fact(DisplayName = "Get user by ID returns user")]
public async Task GetAuthorById_Positive()
{
var @event = new UserCreatedEvent(
UserId: Guid.NewGuid().ToString(),
Username: "compartmental",
DisplayName: "Степной ишак",
AvatarUrl: null);
// Arrange
await using var scope = _services.CreateAsyncScope();
var authors = scope.ServiceProvider.GetRequiredService<IAuthorRepository>();
var author = await authors.CreateAsync(
id: Guid.NewGuid(),
username: "compartmental",
displayName: "Степной ишак",
avatarUrl: null);

await _harness.Bus.Publish(@event);

var message = await _client.GetAsync($"/api/v1/authors/{@event.UserId}");
// Act
var message = await _client.GetAsync($"/api/v1/authors/{author.Id}");
message.StatusCode.Should().Be(HttpStatusCode.OK);

// Assert
var response = await message.Content.ReadFromJsonAsync<AuthorDto>(GlobalSerializerOptions.SnakeCase);
response.Should().BeEquivalentTo(new AuthorDto
{
Id = Guid.Parse(@event.UserId),
Username = @event.Username,
DisplayName = @event.DisplayName,
AvatarUrl = @event.AvatarUrl
});
response.Should().BeEquivalentTo(author);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,43 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using CrowdParlay.Communication;
using CrowdParlay.Social.Api.v1.DTOs;
using CrowdParlay.Social.Application.Abstractions;
using CrowdParlay.Social.Application.DTOs;
using CrowdParlay.Social.IntegrationTests.Fixtures;
using FluentAssertions;
using MassTransit.Testing;
using Authorization = CrowdParlay.Social.IntegrationTests.Services.Authorization;
using Microsoft.Extensions.DependencyInjection;

namespace CrowdParlay.Social.IntegrationTests.Tests;

public class CommentsControllerTests : IClassFixture<WebApplicationContext>
{
private readonly HttpClient _client;
private readonly ITestHarness _harness;
private readonly IServiceProvider _services;

public CommentsControllerTests(WebApplicationContext context)
{
_client = context.Client;
_harness = context.Harness;
_services = context.Services;
}

[Fact(DisplayName = "Search comments returns comments")]
public async Task SearchComments_Positive()
{
var authorId = Guid.NewGuid();

// Create author
var @event = new UserCreatedEvent(
UserId: authorId.ToString(),
Username: "drcrxwn",
DisplayName: "Степной ишак",
AvatarUrl: null);

await _harness.Bus.Publish(@event);
// Arrange
await using var scope = _services.CreateAsyncScope();
var authors = scope.ServiceProvider.GetRequiredService<IAuthorRepository>();
var author = await authors.CreateAsync(
id: Guid.NewGuid(),
username: "drcrxwn",
displayName: "Степной ишак",
avatarUrl: null);

// Create discussion
var serializedCreateDiscussionRequest = JsonSerializer.Serialize(
new DiscussionRequest("Test discussion", "Something"),
GlobalSerializerOptions.SnakeCase);

var accessToken = Authorization.ProduceAccessToken(@event.UserId);
var accessToken = Authorization.ProduceAccessToken(author.Id);
var createDiscussionResponse = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Post, "/api/v1/discussions")
{
Content = new StringContent(serializedCreateDiscussionRequest, Encoding.UTF8, "application/json"),
Expand Down Expand Up @@ -78,38 +74,39 @@ public async Task SearchComments_Positive()

createSecondCommentResponse.StatusCode.Should().Be(HttpStatusCode.Created);

var getCommentsResponse =
await _client.GetAsync($"/api/v1/comments?discussionId={discussion.Id}&page=0&size=3");
// Act
var getCommentsResponse = await _client.GetAsync($"/api/v1/comments?discussionId={discussion.Id}&page=0&size=3");
var comments = await getCommentsResponse.Content.ReadFromJsonAsync<IEnumerable<CommentDto>>(GlobalSerializerOptions.SnakeCase);

// Assert
var commentList = comments.Should().NotBeNullOrEmpty()
.And.Subject.ToList();

commentList.Should().HaveCount(2)
.And.OnlyContain(comment => comment.ReplyCount == 0)
.And.OnlyContain(comment => comment.Author.Id == authorId)
.And.OnlyContain(comment => comment.Author.Id == author.Id)
.And.Contain(comment => comment.Content == "This is the first comment.")
.And.Contain(comment => comment.Content == "This is the second comment.");
}

[Fact(DisplayName = "Reply to comment creates reply")]
public async Task ReplyToComment_Positive()
{
// Create author
var @event = new UserCreatedEvent(
UserId: Guid.NewGuid().ToString(),
Username: "zendet",
DisplayName: "Z E N D E T",
AvatarUrl: null);

await _harness.Bus.Publish(@event);
// Arrange
await using var scope = _services.CreateAsyncScope();
var authors = scope.ServiceProvider.GetRequiredService<IAuthorRepository>();
var author = await authors.CreateAsync(
id: Guid.NewGuid(),
username: "zendet",
displayName: "Z E N D E T",
avatarUrl: null);

// Create discussion
var serializedCreateDiscussionRequest = JsonSerializer.Serialize(
new DiscussionRequest("Test discussion", "Something"),
GlobalSerializerOptions.SnakeCase);

var accessToken = Authorization.ProduceAccessToken(@event.UserId);
var accessToken = Authorization.ProduceAccessToken(author.Id);
var createDiscussionResponse = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Post, "/api/v1/discussions")
{
Content = new StringContent(serializedCreateDiscussionRequest, Encoding.UTF8, "application/json"),
Expand Down Expand Up @@ -146,12 +143,12 @@ public async Task ReplyToComment_Positive()

createReplyResponse.StatusCode.Should().Be(HttpStatusCode.Created);

// Get parent comment
// Assert
var getCommentResponse = await _client.GetAsync($"/api/v1/comments/{comment.Id}");
getCommentResponse.StatusCode.Should().Be(HttpStatusCode.OK);
comment = await getCommentResponse.Content.ReadFromJsonAsync<CommentDto>(GlobalSerializerOptions.SnakeCase);

comment!.ReplyCount.Should().Be(1);
comment.FirstRepliesAuthors.Should().ContainSingle(x => x.Id == Guid.Parse(@event.UserId));
comment.FirstRepliesAuthors.Should().ContainSingle(x => x.Id == author.Id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,43 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using CrowdParlay.Communication;
using CrowdParlay.Social.Api.v1.DTOs;
using CrowdParlay.Social.Application.Abstractions;
using CrowdParlay.Social.Application.DTOs;
using CrowdParlay.Social.IntegrationTests.Fixtures;
using FluentAssertions;
using MassTransit.Testing;
using Authorization = CrowdParlay.Social.IntegrationTests.Services.Authorization;
using Microsoft.Extensions.DependencyInjection;

namespace CrowdParlay.Social.IntegrationTests.Tests;

public class DiscussionsControllerTests : IClassFixture<WebApplicationContext>
{
private readonly HttpClient _client;
private readonly ITestHarness _harness;
private readonly IServiceProvider _services;

public DiscussionsControllerTests(WebApplicationContext context)
{
_client = context.Client;
_harness = context.Harness;
_services = context.Services;
}

[Fact(DisplayName = "Get discussion by ID returns discussion with author")]
[Fact(DisplayName = "Get discussion by ID returns discussion")]
public async Task GetDiscussionByIdHasAuthor_Positive()
{
// Create author
var @event = new UserCreatedEvent(
UserId: Guid.NewGuid().ToString(),
Username: "zendef566t",
DisplayName: "Z E N D E T",
AvatarUrl: null);

await _harness.Bus.Publish(@event);
// Arrange
await using var scope = _services.CreateAsyncScope();
var authors = scope.ServiceProvider.GetRequiredService<IAuthorRepository>();
var author = await authors.CreateAsync(
id: Guid.NewGuid(),
username: "zendef566t",
displayName: "Z E N D E T",
avatarUrl: null);

// Create discussion
var serializedCreateDiscussionRequest = JsonSerializer.Serialize(
new DiscussionRequest("Test discussion", "Something"),
GlobalSerializerOptions.SnakeCase);

var accessToken = Authorization.ProduceAccessToken(@event.UserId);
var accessToken = Authorization.ProduceAccessToken(author.Id);
var createDiscussionResponse = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Post, "/api/v1/discussions")
{
Content = new StringContent(serializedCreateDiscussionRequest, Encoding.UTF8, "application/json"),
Expand All @@ -50,17 +48,12 @@ public async Task GetDiscussionByIdHasAuthor_Positive()
createDiscussionResponse.Should().HaveStatusCode(HttpStatusCode.Created);
var discussionId = (await createDiscussionResponse.Content.ReadFromJsonAsync<DiscussionDto>(GlobalSerializerOptions.SnakeCase))!.Id;

// Get discussion
// Act
var getDiscussionResponse = await _client.GetAsync($"/api/v1/discussions/{discussionId}");
getDiscussionResponse.StatusCode.Should().Be(HttpStatusCode.OK);
var discussion = await getDiscussionResponse.Content.ReadFromJsonAsync<CommentDto>(GlobalSerializerOptions.SnakeCase);

discussion!.Author.Should().BeEquivalentTo(new AuthorDto
{
Id = Guid.Parse(@event.UserId),
Username = @event.Username,
DisplayName = @event.DisplayName,
AvatarUrl = @event.AvatarUrl
});
// Assert
discussion!.Author.Should().BeEquivalentTo(author);
}
}
4 changes: 3 additions & 1 deletion tests/CrowdParlay.Social.IntegrationTests/Usings.cs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
global using Xunit;
global using Xunit;
global using FluentAssertions;
global using Authorization = CrowdParlay.Social.IntegrationTests.Services.Authorization;

0 comments on commit 8123416

Please sign in to comment.