-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathParcelControllerIntegrationTests.cs
More file actions
145 lines (128 loc) · 5.81 KB
/
Copy pathParcelControllerIntegrationTests.cs
File metadata and controls
145 lines (128 loc) · 5.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ParcelTracking.Infrastructure.Data;
using ParcelTracking.Application.DTOs.Parcels.Requests;
using ParcelTracking.Application.DTOs.Common;
using ParcelTracking.Domain.Enums;
using ParcelTracking.Domain.Entities;
using Xunit;
namespace ParcelTracking.API.IntegrationTests
{
/// <summary>
/// Integration tests for the Parcels Controller endpoints.
///
/// These tests require a PostgreSQL database. To run with Docker:
/// docker run -d --name parceltrack-test-db -e POSTGRES_USER=test -e POSTGRES_PASSWORD=test -e POSTGRES_DB=parceltracking_test -p 5433:5432 postgres:15
///
/// Then update the connection string in this test class to point to your database instance.
/// </summary>
public class ParcelApiTests : IAsyncLifetime
{
private WebApplicationFactory<Program>? _factory;
private HttpClient? _client;
private string? _connectionString;
public async Task InitializeAsync()
{
// Use a connection string pointing to a running Postgres instance
// Set via environment variable or hardcode for testing (NOT RECOMMENDED for production)
_connectionString = Environment.GetEnvironmentVariable("PARCELTRACK_TEST_DB")
?? "Host=localhost;Port=5433;Database=parceltracking_test;Username=test;Password=test;Pooling=false;";
// Attempt to create the factory with the test database
try
{
_factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((context, cfg) =>
{
var inMemConfig = new Dictionary<string, string?>
{
{"ConnectionStrings:DefaultConnection", _connectionString}
};
cfg.AddInMemoryCollection(inMemConfig);
});
});
_client = _factory.CreateClient();
// Ensure database is created and migrated
var options = new DbContextOptionsBuilder<ParcelTrackingDbContext>()
.UseNpgsql(_connectionString)
.Options;
using (var db = new ParcelTrackingDbContext(options))
{
db.Database.EnsureCreated();
}
}
catch (Exception)
{
// If Docker PostgreSQL is not available, silently skip this test
// This allows the unit tests to pass on systems without Docker
_connectionString = null;
_factory?.Dispose();
_factory = null;
_client = null;
}
}
public async Task DisposeAsync()
{
_client?.Dispose();
_factory?.Dispose();
}
[Fact]
public async Task RegisterParcel_ReturnsCreatedAndEstimatedDeliveryHasLocal1700()
{
// Skip test if Docker database is not available
if (_client == null || _connectionString == null)
{
throw new SkipTestException("PostgreSQL database not available. Start Docker container with: docker run -d --name parceltrack-test-db -e POSTGRES_USER=test -e POSTGRES_PASSWORD=test -e POSTGRES_DB=parceltracking_test -p 5433:5432 postgres:15");
}
// Arrange: seed addresses
var options = new DbContextOptionsBuilder<ParcelTrackingDbContext>()
.UseNpgsql(_connectionString)
.Options;
Guid shipperId, recipientId;
using (var db = new ParcelTrackingDbContext(options))
{
db.Database.EnsureCreated();
var shipper = new Address { Id = Guid.NewGuid(), CountryCode = "US", City = "NYC", Street1 = "S" };
var recipient = new Address { Id = Guid.NewGuid(), CountryCode = "US", City = "Boston", Street1 = "R" };
db.Addresses.Add(shipper);
db.Addresses.Add(recipient);
await db.SaveChangesAsync();
shipperId = shipper.Id;
recipientId = recipient.Id;
}
var req = new RegisterParcelRequest
{
ShipperAddressId = shipperId,
RecipientAddressId = recipientId,
ServiceType = ServiceType.Standard,
Weight = new WeightDto { Value = 1m, Unit = Domain.Enums.WeightUnit.Kg },
Dimensions = new DimensionsDto { Length = 1, Width = 1, Height = 1, Unit = Domain.Enums.DimensionUnit.Cm },
DeclaredValue = new DeclaredValueDto { Amount = 1m, Currency = "USD" }
};
// Act
var response = await _client!.PostAsJsonAsync("api/v1/Parcels", req);
// Assert
response.StatusCode.Should().Be(System.Net.HttpStatusCode.Created);
var created = await response.Content.ReadFromJsonAsync<ParcelTracking.Application.DTOs.Parcels.ParcelDto>();
created.Should().NotBeNull();
created!.EstimatedDeliveryDate.Hour.Should().Be(17);
}
}
/// <summary>
/// Custom exception to skip integration tests when infrastructure is not available.
/// </summary>
public class SkipTestException : Exception
{
public SkipTestException(string message) : base(message) { }
}
}