Skip to content

Commit d0fc21a

Browse files
authored
Merge pull request #8 from csvitor-dev/tests/API-integration-test-cases
`develop` <- `tests/API-integration-test-cases`
2 parents 295e649 + c14d777 commit d0fc21a

18 files changed

Lines changed: 325 additions & 51 deletions

File tree

RecipesApp.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validators.Test", "test\Val
2929
EndProject
3030
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UseCases.Test", "test\UseCases.Test\UseCases.Test.csproj", "{FAE3D4EC-E66B-4C4E-913A-1E49F4D46C5D}"
3131
EndProject
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Test", "test\API.Test\API.Test.csproj", "{D82F1550-371B-4C6D-8CAE-3DCD1B0984E2}"
33+
EndProject
3234
Global
3335
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3436
Debug|Any CPU = Debug|Any CPU
@@ -71,6 +73,10 @@ Global
7173
{FAE3D4EC-E66B-4C4E-913A-1E49F4D46C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
7274
{FAE3D4EC-E66B-4C4E-913A-1E49F4D46C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
7375
{FAE3D4EC-E66B-4C4E-913A-1E49F4D46C5D}.Release|Any CPU.Build.0 = Release|Any CPU
76+
{D82F1550-371B-4C6D-8CAE-3DCD1B0984E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
77+
{D82F1550-371B-4C6D-8CAE-3DCD1B0984E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
78+
{D82F1550-371B-4C6D-8CAE-3DCD1B0984E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
79+
{D82F1550-371B-4C6D-8CAE-3DCD1B0984E2}.Release|Any CPU.Build.0 = Release|Any CPU
7480
EndGlobalSection
7581
GlobalSection(SolutionProperties) = preSolution
7682
HideSolutionNode = FALSE
@@ -87,6 +93,7 @@ Global
8793
{57ADA9DB-D6F6-4D89-8D1F-64894A1D0451} = {C1D0FD22-94B4-4FC6-AD0A-8FB3F188E0EE}
8894
{993F9D03-5E41-4B0F-8C63-4ADB422814EE} = {C1D0FD22-94B4-4FC6-AD0A-8FB3F188E0EE}
8995
{FAE3D4EC-E66B-4C4E-913A-1E49F4D46C5D} = {C1D0FD22-94B4-4FC6-AD0A-8FB3F188E0EE}
96+
{D82F1550-371B-4C6D-8CAE-3DCD1B0984E2} = {C1D0FD22-94B4-4FC6-AD0A-8FB3F188E0EE}
9097
EndGlobalSection
9198
GlobalSection(ExtensibilityGlobals) = postSolution
9299
SolutionGuid = {655B2453-B859-4205-B05E-64082CF48732}

docker-compose.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
services:
2+
mssql:
3+
image: mcr.microsoft.com/mssql/server:2022-latest
4+
container_name: asp-net-mssql
5+
environment:
6+
- SA_PASSWORD=@PassWord123
7+
- ACCEPT_EULA=Y
8+
- MSSQL_PID=Developer
9+
- MSSQL_DATABASE=recipes_app_db
10+
ports:
11+
- 1433:1433
12+
volumes:
13+
- mssql_data:/var/opt/mssql
14+
restart: unless-stopped
15+
16+
volumes:
17+
mssql_data:

src/BackEnd/RecipesApp.API/Program.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242

4343
void MigrateDb(IConfiguration configuration)
4444
{
45+
if (configuration.IsTesting())
46+
return;
47+
4548
var scope = app.Services
4649
.GetRequiredService<IServiceScopeFactory>().CreateScope();
4750

@@ -50,3 +53,5 @@ void MigrateDb(IConfiguration configuration)
5053
scope.ServiceProvider
5154
);
5255
}
56+
57+
public partial class Program;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"EnvironmentTesting": true,
3+
"Logging": {
4+
"LogLevel": {
5+
"Default": "Information",
6+
"Microsoft.AspNetCore": "Warning"
7+
}
8+
},
9+
"Settings": {
10+
"key": "dot"
11+
}
12+
}

src/BackEnd/RecipesApp.Infra/Extensions/InfrastructureConfigurationExtension.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,11 @@ public static class InfrastructureConfigurationExtension
66
{
77
public static string ConnectionString(this IConfiguration configuration)
88
=> configuration.GetConnectionString("db")!;
9+
10+
public static bool IsTesting(this IConfiguration configuration)
11+
{
12+
var sectionValue = configuration["EnvironmentTesting"];
13+
14+
return sectionValue?.ToLower().Equals("true") ?? false;
15+
}
916
}

src/BackEnd/RecipesApp.Infra/Extensions/InfrastructureDIExtension.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ public static class InfrastructureDIExtension
1414
{
1515
public static void AddInfra(this IServiceCollection self, IConfiguration configuration)
1616
{
17-
AddDbContext(self,
18-
configuration.ConnectionString());
19-
AddFluentMigrator(self, configuration.ConnectionString());
2017
AddRepositories(self);
18+
19+
if (configuration.IsTesting())
20+
return;
21+
22+
AddDbContext(self, configuration.ConnectionString());
23+
AddFluentMigrator(self, configuration.ConnectionString());
2124
}
2225

2326
private static void AddDbContext(IServiceCollection services, string? connection)
Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,60 @@
1-
namespace RecipesApp.Exception.Resources;
1+
using System.Globalization;
2+
3+
namespace RecipesApp.Exception.Resources;
24

35
public static class ResourcesAccessor
46
{
5-
public static string EMAIL_ALREADY_REGISTERED { get
6-
=> ExceptionMessagesResource.EMAIL_ALREADY_REGISTERED; }
7-
public static string EMAIL_INVALID { get
8-
=> ExceptionMessagesResource.EMAIL_INVALID; }
9-
public static string EMAIL_REQUIRED { get
10-
=> ExceptionMessagesResource.EMAIL_REQUIRED; }
11-
public static string NAME_REQUIRED { get
12-
=> ExceptionMessagesResource.NAME_REQUIRED; }
13-
public static string PASSWORD_LENGTH { get
14-
=> ExceptionMessagesResource.PASSWORD_LENGTH; }
15-
public static string PASSWORD_REQUIRED { get
16-
=> ExceptionMessagesResource.PASSWORD_REQUIRED; }
17-
public static string UNKNOWN_ERROR { get
18-
=> ExceptionMessagesResource.UNKNOWN_ERROR; }
19-
public static string SERVICE_FAIL { get
20-
=> ExceptionMessagesResource.SERVICE_FAIL; }
21-
}
7+
public static string EMAIL_ALREADY_REGISTERED
8+
{
9+
get
10+
=> ExceptionMessagesResource.EMAIL_ALREADY_REGISTERED;
11+
}
12+
13+
public static string EMAIL_INVALID
14+
{
15+
get
16+
=> ExceptionMessagesResource.EMAIL_INVALID;
17+
}
18+
19+
public static string EMAIL_REQUIRED
20+
{
21+
get
22+
=> ExceptionMessagesResource.EMAIL_REQUIRED;
23+
}
24+
25+
public static string NAME_REQUIRED
26+
{
27+
get
28+
=> ExceptionMessagesResource.NAME_REQUIRED;
29+
}
30+
31+
public static string PASSWORD_LENGTH
32+
{
33+
get
34+
=> ExceptionMessagesResource.PASSWORD_LENGTH;
35+
}
36+
37+
public static string PASSWORD_REQUIRED
38+
{
39+
get
40+
=> ExceptionMessagesResource.PASSWORD_REQUIRED;
41+
}
42+
43+
public static string UNKNOWN_ERROR
44+
{
45+
get
46+
=> ExceptionMessagesResource.UNKNOWN_ERROR;
47+
}
48+
49+
public static string SERVICE_FAIL
50+
{
51+
get
52+
=> ExceptionMessagesResource.SERVICE_FAIL;
53+
}
54+
55+
public static string GetMessageByCulture(string field, string? culture)
56+
{
57+
var cultureInfo = new CultureInfo(culture ?? "en");
58+
return ExceptionMessagesResource.ResourceManager.GetString(field, cultureInfo)!;
59+
}
60+
}

test/API.Test/API.Test.csproj

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
14+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
15+
<PackageReference Include="xunit" Version="2.5.3"/>
16+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<Using Include="Xunit"/>
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<ProjectReference Include="..\CommonTestUtilities\CommonTestUtilities.csproj" />
25+
</ItemGroup>
26+
27+
</Project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Collections;
2+
3+
namespace API.Test.InlineData;
4+
5+
internal class CultureInlineData : IEnumerable<object?[]>
6+
{
7+
public IEnumerator<object?[]> GetEnumerator()
8+
{
9+
yield return [null];
10+
yield return ["en-US"];
11+
yield return ["pt-BR"];
12+
}
13+
14+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
15+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using System.Net;
2+
using System.Net.Http.Json;
3+
using System.Text.Json;
4+
using API.Test.InlineData;
5+
using CommonTestUtilities.Requests;
6+
using CommonTestUtilities.Services;
7+
using RecipesApp.Exception.Resources;
8+
9+
namespace API.Test.User.Register;
10+
11+
public class RegisterUserEndpoint(WebApplicationMockFactory factory)
12+
: IClassFixture<WebApplicationMockFactory>
13+
{
14+
private readonly HttpClient _client = factory.CreateClient();
15+
16+
[Fact]
17+
public async Task Test_OnSuccess()
18+
{
19+
var request = RegisterUserRequestJSONMockFactory.CreateMock();
20+
21+
var response = await _client.PostAsJsonAsync("/Users", request);
22+
await using var body = await response.Content.ReadAsStreamAsync();
23+
var result = await JsonDocument.ParseAsync(body);
24+
var username = result.RootElement.GetProperty("name").GetString();
25+
26+
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
27+
Assert.False(string.IsNullOrWhiteSpace(username));
28+
Assert.Equal(request.Name, username);
29+
}
30+
31+
[Theory]
32+
[ClassData(typeof(CultureInlineData))]
33+
public async Task Test_EmptyName_OnFailure(string? culture)
34+
{
35+
_client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", culture);
36+
var request = RegisterUserRequestJSONMockFactory.CreateMockWithoutName();
37+
38+
var response = await _client.PostAsJsonAsync("/Users", request);
39+
await using var body = await response.Content.ReadAsStreamAsync();
40+
var result = await JsonDocument.ParseAsync(body);
41+
var errors = result.RootElement.GetProperty("errors")
42+
.EnumerateArray().ToList();
43+
44+
var expectedMessage = ResourcesAccessor.GetMessageByCulture("NAME_REQUIRED", culture);
45+
46+
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
47+
Assert.Single(errors,
48+
error => error.GetString()!.Equals(expectedMessage));
49+
}
50+
51+
[Theory]
52+
[ClassData(typeof(CultureInlineData))]
53+
public async Task Test_EmptyEmail_OnFailure(string? culture)
54+
{
55+
_client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", culture);
56+
var request = RegisterUserRequestJSONMockFactory.CreateMockWithoutEmail();
57+
58+
var response = await _client.PostAsJsonAsync("/Users", request);
59+
await using var body = await response.Content.ReadAsStreamAsync();
60+
var result = await JsonDocument.ParseAsync(body);
61+
var errors = result.RootElement.GetProperty("errors")
62+
.EnumerateArray().ToList();
63+
64+
var expectedMessage = ResourcesAccessor.GetMessageByCulture("EMAIL_REQUIRED", culture);
65+
66+
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
67+
Assert.Single(errors,
68+
error => error.GetString()!.Equals(expectedMessage));
69+
}
70+
71+
[Theory]
72+
[ClassData(typeof(CultureInlineData))]
73+
public async Task Test_InvalidEmail_OnFailure(string? culture)
74+
{
75+
_client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", culture);
76+
var request = RegisterUserRequestJSONMockFactory.CreateMockWithInvalidEmail("email.com");
77+
78+
var response = await _client.PostAsJsonAsync("/Users", request);
79+
await using var body = await response.Content.ReadAsStreamAsync();
80+
var result = await JsonDocument.ParseAsync(body);
81+
var errors = result.RootElement.GetProperty("errors")
82+
.EnumerateArray().ToList();
83+
84+
var expectedMessage = ResourcesAccessor.GetMessageByCulture("EMAIL_INVALID", culture);
85+
86+
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
87+
Assert.Single(errors,
88+
error => error.GetString()!.Equals(expectedMessage));
89+
}
90+
91+
[Theory]
92+
[ClassData(typeof(CultureInlineData))]
93+
public async Task Test_EmptyPassword_OnFailure(string? culture)
94+
{
95+
_client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", culture);
96+
var request = RegisterUserRequestJSONMockFactory.CreateMockWithoutPassword();
97+
98+
var response = await _client.PostAsJsonAsync("/Users", request);
99+
await using var body = await response.Content.ReadAsStreamAsync();
100+
var result = await JsonDocument.ParseAsync(body);
101+
var errors = result.RootElement.GetProperty("errors")
102+
.EnumerateArray().ToList();
103+
104+
var expectedMessage = ResourcesAccessor.GetMessageByCulture("PASSWORD_REQUIRED", culture);
105+
106+
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
107+
Assert.Single(errors,
108+
error => error.GetString()!.Equals(expectedMessage));
109+
}
110+
}

0 commit comments

Comments
 (0)