campus-errand/server.tests/OrderDetailByStatusPropertyTests.cs
2026-03-12 18:12:10 +08:00

239 lines
9.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using CampusErrand.Data;
using CampusErrand.Models;
using CampusErrand.Models.Dtos;
using FsCheck;
using FsCheck.Xunit;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace CampusErrand.Tests;
/// <summary>
/// Property 19: 订单详情按状态显示字段
/// 对任意订单,当状态为"待接单"时接单时间、跑腿信息、完成信息应为空;
/// 当状态为"进行中"时应显示接单时间和跑腿信息;
/// 当状态为"已完成"时应显示所有信息。
/// **Feature: login-and-homepage, Property 19: 订单详情按状态显示字段**
///
/// </summary>
public class OrderDetailByStatusPropertyTests : IDisposable
{
private const string JwtSecret = "YourSuperSecretKeyForJwtTokenGeneration_AtLeast32Chars!";
private const string JwtIssuer = "CampusErrand";
private const string JwtAudience = "CampusErrandApp";
private readonly List<WebApplicationFactory<Program>> _factories = [];
private WebApplicationFactory<Program> CreateFactory(string dbName)
{
var factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
var efDescriptors = services
.Where(d =>
d.ServiceType.FullName?.Contains("EntityFrameworkCore") == true
|| d.ServiceType == typeof(DbContextOptions<AppDbContext>)
|| d.ServiceType == typeof(DbContextOptions)
|| d.ImplementationType?.FullName?.Contains("EntityFrameworkCore") == true)
.ToList();
foreach (var d in efDescriptors) services.Remove(d);
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase(dbName));
});
});
_factories.Add(factory);
return factory;
}
private static string GenerateToken(int userId, string role = "User")
{
var key = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(
System.Text.Encoding.UTF8.GetBytes(JwtSecret));
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(
key, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.NameIdentifier, userId.ToString()),
new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, role)
};
var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(
issuer: JwtIssuer, audience: JwtAudience, claims: claims,
expires: DateTime.UtcNow.AddHours(1), signingCredentials: credentials);
return new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler().WriteToken(token);
}
/// <summary>
/// 属性:待接单状态的订单,接单时间、跑腿信息、完成信息应为空
/// </summary>
[Property(MaxTest = 20)]
public bool (PositiveInt seed)
{
var dbName = $"detail_pending_{Guid.NewGuid()}";
using var factory = CreateFactory(dbName);
var ownerId = 100;
int orderId;
using (var scope = factory.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Users.Add(new User
{
Id = ownerId, OpenId = $"owner_{Guid.NewGuid()}", Phone = "13900000001",
Nickname = "单主", CreatedAt = DateTime.UtcNow
});
var order = new Order
{
OrderNo = $"ORD{Guid.NewGuid():N}"[..20],
OwnerId = ownerId,
OrderType = OrderType.Pickup, Status = OrderStatus.Pending,
ItemName = "测试物品", DeliveryLocation = "测试地点",
Phone = "13800138000", Commission = 5.0m, TotalAmount = 5.0m,
CreatedAt = DateTime.UtcNow
};
db.Orders.Add(order);
db.SaveChanges();
orderId = order.Id;
}
var client = factory.CreateClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", GenerateToken(ownerId));
var response = client.GetFromJsonAsync<OrderResponse>($"/api/orders/{orderId}").Result!;
// 待接单接单时间、跑腿昵称、跑腿UID、完成时间、完成凭证应为空
return response.AcceptedAt == null
&& response.RunnerNickname == null
&& response.RunnerUid == null
&& response.CompletedAt == null
&& response.CompletionProof == null;
}
/// <summary>
/// 属性:进行中状态的订单,应显示接单时间和跑腿信息
/// </summary>
[Property(MaxTest = 20)]
public bool (PositiveInt seed)
{
var dbName = $"detail_inprogress_{Guid.NewGuid()}";
using var factory = CreateFactory(dbName);
var ownerId = 100;
var runnerId = 200;
int orderId;
using (var scope = factory.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Users.Add(new User
{
Id = ownerId, OpenId = $"owner_{Guid.NewGuid()}", Phone = "13900000001",
Nickname = "单主", CreatedAt = DateTime.UtcNow
});
db.Users.Add(new User
{
Id = runnerId, OpenId = $"runner_{Guid.NewGuid()}", Phone = "13900000002",
Nickname = "跑腿小哥", Role = UserRole.Runner, CreatedAt = DateTime.UtcNow
});
var order = new Order
{
OrderNo = $"ORD{Guid.NewGuid():N}"[..20],
OwnerId = ownerId, RunnerId = runnerId,
OrderType = OrderType.Delivery, Status = OrderStatus.InProgress,
ItemName = "测试物品", DeliveryLocation = "测试地点",
Phone = "13800138000", Commission = 5.0m, TotalAmount = 5.0m,
CreatedAt = DateTime.UtcNow, AcceptedAt = DateTime.UtcNow
};
db.Orders.Add(order);
db.SaveChanges();
orderId = order.Id;
}
var client = factory.CreateClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", GenerateToken(ownerId));
var response = client.GetFromJsonAsync<OrderResponse>($"/api/orders/{orderId}").Result!;
// 进行中:应显示接单时间和跑腿信息,完成信息为空
return response.AcceptedAt != null
&& response.RunnerNickname == "跑腿小哥"
&& response.RunnerUid == runnerId
&& response.CompletedAt == null
&& response.CompletionProof == null;
}
/// <summary>
/// 属性:已完成状态的订单,应显示所有信息
/// </summary>
[Property(MaxTest = 20)]
public bool (PositiveInt seed)
{
var dbName = $"detail_completed_{Guid.NewGuid()}";
using var factory = CreateFactory(dbName);
var ownerId = 100;
var runnerId = 200;
int orderId;
using (var scope = factory.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Users.Add(new User
{
Id = ownerId, OpenId = $"owner_{Guid.NewGuid()}", Phone = "13900000001",
Nickname = "单主", CreatedAt = DateTime.UtcNow
});
db.Users.Add(new User
{
Id = runnerId, OpenId = $"runner_{Guid.NewGuid()}", Phone = "13900000002",
Nickname = "跑腿小哥", Role = UserRole.Runner, CreatedAt = DateTime.UtcNow
});
var order = new Order
{
OrderNo = $"ORD{Guid.NewGuid():N}"[..20],
OwnerId = ownerId, RunnerId = runnerId,
OrderType = OrderType.Purchase, Status = OrderStatus.Completed,
ItemName = "测试物品", DeliveryLocation = "测试地点",
Phone = "13800138000", Commission = 5.0m, GoodsAmount = 20.0m, TotalAmount = 25.0m,
CompletionProof = "https://img.test/proof.jpg",
CreatedAt = DateTime.UtcNow, AcceptedAt = DateTime.UtcNow,
CompletedAt = DateTime.UtcNow
};
db.Orders.Add(order);
db.SaveChanges();
orderId = order.Id;
}
var client = factory.CreateClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", GenerateToken(ownerId));
var response = client.GetFromJsonAsync<OrderResponse>($"/api/orders/{orderId}").Result!;
// 已完成:应显示接单时间、跑腿信息、完成时间和完成凭证
return response.AcceptedAt != null
&& response.RunnerNickname == "跑腿小哥"
&& response.RunnerUid == runnerId
&& response.CompletedAt != null
&& response.CompletionProof == "https://img.test/proof.jpg";
}
public void Dispose()
{
foreach (var f in _factories) f.Dispose();
_factories.Clear();
}
}