Skip to content

Commit 7b6b6d0

Browse files
Merge pull request #111 from boolean-uk/107-backend---streamline-testing-with-authorized-endpoints
Refactor, added BaseIntegrationTest
2 parents a82ea05 + 7abf792 commit 7b6b6d0

File tree

6 files changed

+313
-269
lines changed

6 files changed

+313
-269
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using exercise.wwwapi.DTOs.Login;
2+
using Microsoft.AspNetCore.Mvc.Testing;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Net.Http.Headers;
7+
using System.Text;
8+
using System.Text.Json;
9+
using System.Text.Json.Nodes;
10+
using System.Threading.Tasks;
11+
12+
namespace exercise.tests.IntegrationTests
13+
{
14+
public static class HttpResponseExtensions
15+
{
16+
public static async Task<JsonNode?> ReadJsonAsync(this HttpResponseMessage response)
17+
{
18+
var contentString = await response.Content.ReadAsStringAsync();
19+
return string.IsNullOrWhiteSpace(contentString)
20+
? null
21+
: JsonNode.Parse(contentString);
22+
}
23+
}
24+
public abstract class BaseIntegrationTest
25+
{
26+
protected WebApplicationFactory<Program> _factory;
27+
protected HttpClient _client;
28+
29+
[SetUp]
30+
public void BaseSetup()
31+
{
32+
_factory = new WebApplicationFactory<Program>();
33+
_client = _factory.CreateClient();
34+
}
35+
36+
[TearDown]
37+
public void BaseTearDown()
38+
{
39+
_client?.Dispose();
40+
_factory?.Dispose();
41+
}
42+
43+
44+
// IF CHANGES DONE TO THE SEEDER, RECHECK THESE USERS
45+
// SQL QUERY TO CHECK IF USER HAS ATLEAST ONE POST AND ATLEAST ONE COMMENT
46+
/*
47+
SELECT
48+
u.id AS user_id,
49+
u.email,
50+
u.role,
51+
ARRAY_AGG(DISTINCT p.id) AS post_ids,
52+
ARRAY_AGG(DISTINCT c.id) AS comment_ids
53+
FROM users u
54+
JOIN posts p ON u.id = p.userid
55+
JOIN comments c ON u.id = c.userid
56+
WHERE u.role = 'student'
57+
GROUP BY u.id, u.email, u.role, u.passwordhash;
58+
*/
59+
protected const string TeacherEmail = "[email protected]"; // has post id 34,35 and comment id 37
60+
protected const string TeacherPassword = "Neidintulling!l33t";
61+
protected const int TeacherPostID = 34;
62+
protected const int TeacherCommentID = 37;
63+
64+
protected const string StudentEmail1 = "[email protected]"; //id 232, has post id 57, 58 and comment id 2
65+
protected const string StudentPassword1 = "SuperHash!4";
66+
protected const int StudentPostID1 = 57;
67+
protected const int StudentCommentID1 = 2;
68+
69+
protected const string StudentEmail2 = "[email protected]"; //id 85, has post id 36 and comment id 3
70+
protected const string StudentPassword2 = "Neidintulling!l33t";
71+
protected const int StudentPostID2 = 36;
72+
protected const int StudentCommentID2 = 3;
73+
74+
75+
protected async Task<string> LoginAndGetToken(string email, string password, bool success = true)
76+
{
77+
var loginBody = new LoginRequestDTO { email = email, password = password };
78+
var loginRequestBody = new StringContent(
79+
JsonSerializer.Serialize(loginBody),
80+
Encoding.UTF8,
81+
"application/json"
82+
);
83+
84+
var loginResponse = await _client.PostAsync("/login", loginRequestBody);
85+
//loginResponse.EnsureSuccessStatusCode();
86+
87+
var loginContent = await loginResponse.Content.ReadAsStringAsync();
88+
var loginMessage = JsonNode.Parse(loginContent);
89+
string? token = loginMessage?["data"]?["token"]?.GetValue<string>();
90+
91+
Assert.That(token, success ? Is.Not.Null : Is.Null);
92+
93+
return token;
94+
}
95+
96+
// Helper methods
97+
protected async Task<HttpResponseMessage> SendAuthenticatedRequestAsync<T>(
98+
HttpMethod method,
99+
string endpoint,
100+
string token,
101+
T? body = default
102+
)
103+
{
104+
var request = new HttpRequestMessage(method, endpoint);
105+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
106+
107+
if (body != null)
108+
{
109+
var json = JsonSerializer.Serialize(body);
110+
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
111+
}
112+
113+
return await _client.SendAsync(request);
114+
}
115+
116+
protected async Task<HttpResponseMessage> SendAuthenticatedGetAsync(string endpoint, string token)
117+
{
118+
return await SendAuthenticatedRequestAsync<object>(HttpMethod.Get, endpoint, token);
119+
}
120+
121+
protected async Task<HttpResponseMessage> SendAuthenticatedPostAsync<T>(string endpoint, string token, T body)
122+
{
123+
return await SendAuthenticatedRequestAsync(HttpMethod.Post, endpoint, token, body);
124+
}
125+
protected async Task<HttpResponseMessage> SendAuthenticatedPatchAsync<T>(string endpoint, string token, T body)
126+
{
127+
return await SendAuthenticatedRequestAsync(HttpMethod.Patch, endpoint, token, body);
128+
}
129+
130+
protected async Task<HttpResponseMessage> SendAuthenticatedPutAsync<T>(string endpoint, string token, T body)
131+
{
132+
return await SendAuthenticatedRequestAsync(HttpMethod.Put, endpoint, token, body);
133+
}
134+
135+
protected async Task<HttpResponseMessage> SendAuthenticatedDeleteAsync(string endpoint, string token)
136+
{
137+
return await SendAuthenticatedRequestAsync<object>(HttpMethod.Delete, endpoint, token);
138+
}
139+
140+
}
141+
}

exercise.tests/IntegrationTests/EndpointStatusTest.cs

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,25 @@ namespace exercise.tests.IntegrationTests
1010
/// Integration smoke tests that ensure unexpected endpoints return consistent error responses.
1111
/// </summary>
1212
[TestFixture]
13-
public class EndpointStatusTest
13+
public class EndpointStatusTest : BaseIntegrationTest
1414
{
15-
private WebApplicationFactory<Program> _factory;
16-
private HttpClient _client;
17-
18-
[SetUp]
19-
public void SetUp()
20-
{
21-
// Arrange
22-
_factory = new WebApplicationFactory<Program>();
23-
_client = _factory.CreateClient();
24-
}
25-
26-
[TearDown]
27-
public void TearDown()
28-
{
29-
_client.Dispose();
30-
_factory.Dispose();
31-
}
32-
3315
/// <summary>
3416
/// Verifies POST requests to unknown routes return a 404 with the canonical payload.
3517
/// </summary>
3618
[Test]
3719
public async Task PostCheckInvalidEndpoint()
3820
{
21+
3922
var body = new
4023
{
41-
email = $"[email protected]",
42-
password = "someR21!password"
24+
email = TeacherEmail,
25+
password = TeacherPassword
4326
};
44-
var json = JsonSerializer.Serialize(body);
45-
var requestBody = new StringContent(json, Encoding.UTF8, "application/json");
46-
47-
// Act
48-
var response = await _client.PostAsync("/okokoNONEVER", requestBody);
4927

50-
var contentString = await response.Content.ReadAsStringAsync();
28+
string token = await LoginAndGetToken(TeacherEmail, TeacherPassword);
29+
HttpResponseMessage response = await SendAuthenticatedPostAsync("/NOthisWouldNEVERHAPPENItskindaweird", token, body);
5130

52-
JsonNode? message = null;
53-
if (!string.IsNullOrWhiteSpace(contentString))
54-
{
55-
message = JsonNode.Parse(contentString);
56-
}
57-
58-
var messageText = message?["message"]?.GetValue<string>();
31+
var message = await response.ReadJsonAsync();
5932

6033
Console.WriteLine("Message: " + message);
6134
// Assert
@@ -69,19 +42,13 @@ public async Task PostCheckInvalidEndpoint()
6942
[Test]
7043
public async Task GetCheckInvalidEndpoint()
7144
{
72-
45+
string token = await LoginAndGetToken(TeacherEmail, TeacherPassword);
7346
// Act
74-
var response = await _client.GetAsync("/okokoNONEVER");
47+
HttpResponseMessage response = await SendAuthenticatedGetAsync("/NOthisWouldNEVERHAPPENItskindaweird", token);
7548

76-
var contentString = await response.Content.ReadAsStringAsync();
7749

78-
JsonNode? message = null;
79-
if (!string.IsNullOrWhiteSpace(contentString))
80-
{
81-
message = JsonNode.Parse(contentString);
82-
}
50+
var message = await response.ReadJsonAsync();
8351

84-
var messageText = message?["message"]?.GetValue<string>();
8552

8653
Console.WriteLine("Message: " + message);
8754
// Assert

0 commit comments

Comments
 (0)