309 lines
10 KiB
C#
309 lines
10 KiB
C#
using FsCheck;
|
|
using FsCheck.Xunit;
|
|
using HuangyanParking.Domain.Entities;
|
|
using HuangyanParking.Infrastructure.Data;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace HuangyanParking.Tests;
|
|
|
|
/// <summary>
|
|
/// 管理后台CRUD Round-Trip 属性测试
|
|
/// </summary>
|
|
public class AdminCrudPropertyTests
|
|
{
|
|
/// <summary>创建内存数据库上下文</summary>
|
|
private static AppDbContext CreateDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
|
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
|
.Options;
|
|
return new AppDbContext(options);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — Banner
|
|
/// 创建/更新后查询应得到与输入一致的结果
|
|
/// Validates: Requirements 18.2
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool Banner_CrudRoundTrip_ShouldBeConsistent(
|
|
NonEmptyString imageUrlWrapper, byte sortOrder, bool isActive)
|
|
{
|
|
using var db = CreateDbContext();
|
|
var imageUrl = imageUrlWrapper.Get;
|
|
|
|
// 创建
|
|
var banner = new Banner
|
|
{
|
|
ImageUrl = imageUrl,
|
|
SortOrder = sortOrder,
|
|
IsActive = isActive,
|
|
};
|
|
db.Banners.Add(banner);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证创建
|
|
var queried = db.Banners.Find(banner.Id)!;
|
|
if (queried.ImageUrl != imageUrl || queried.SortOrder != sortOrder || queried.IsActive != isActive)
|
|
return false;
|
|
|
|
// 更新
|
|
var newUrl = imageUrl + "_updated";
|
|
var newSort = (sortOrder + 1) % 256;
|
|
queried.ImageUrl = newUrl;
|
|
queried.SortOrder = newSort;
|
|
queried.IsActive = !isActive;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证更新
|
|
var updated = db.Banners.Find(banner.Id)!;
|
|
return updated.ImageUrl == newUrl
|
|
&& updated.SortOrder == newSort
|
|
&& updated.IsActive == !isActive;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — 门店
|
|
/// 创建/更新后查询应得到与输入一致的结果
|
|
/// Validates: Requirements 18.4
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool Store_CrudRoundTrip_ShouldBeConsistent(
|
|
NonEmptyString nameWrapper, NonEmptyString addressWrapper, bool isActive)
|
|
{
|
|
using var db = CreateDbContext();
|
|
var name = nameWrapper.Get;
|
|
var address = addressWrapper.Get;
|
|
|
|
// 创建
|
|
var store = new Store
|
|
{
|
|
Name = name,
|
|
Address = address,
|
|
Type = "human",
|
|
IsActive = isActive,
|
|
};
|
|
db.Stores.Add(store);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证创建
|
|
var queried = db.Stores.Find(store.Id)!;
|
|
if (queried.Name != name || queried.Address != address || queried.IsActive != isActive)
|
|
return false;
|
|
|
|
// 更新
|
|
var newName = name + "_updated";
|
|
queried.Name = newName;
|
|
queried.Type = "unmanned";
|
|
queried.IsActive = !isActive;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证更新
|
|
var updated = db.Stores.Find(store.Id)!;
|
|
return updated.Name == newName
|
|
&& updated.Type == "unmanned"
|
|
&& updated.IsActive == !isActive;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — 优惠券模板
|
|
/// 创建/更新后查询应得到与输入一致的结果
|
|
/// Validates: Requirements 18.6
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool CouponTemplate_CrudRoundTrip_ShouldBeConsistent(
|
|
NonEmptyString nameWrapper, PositiveInt pointsCostWrapper, PositiveInt totalCountWrapper)
|
|
{
|
|
using var db = CreateDbContext();
|
|
var name = nameWrapper.Get;
|
|
var pointsCost = pointsCostWrapper.Get % 1000 + 1;
|
|
var totalCount = totalCountWrapper.Get % 500 + 1;
|
|
|
|
// 先创建门店(外键依赖)
|
|
var store = new Store { Name = "测试门店", Type = "human" };
|
|
db.Stores.Add(store);
|
|
db.SaveChanges();
|
|
|
|
// 创建优惠券模板
|
|
var template = new CouponTemplate
|
|
{
|
|
Name = name,
|
|
CouponType = "free",
|
|
StoreId = store.Id,
|
|
ValidStart = DateTime.UtcNow,
|
|
ValidEnd = DateTime.UtcNow.AddDays(30),
|
|
TotalCount = totalCount,
|
|
RemainingCount = totalCount,
|
|
PointsCost = pointsCost,
|
|
Source = "platform",
|
|
};
|
|
db.CouponTemplates.Add(template);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证创建
|
|
var queried = db.CouponTemplates.Find(template.Id)!;
|
|
if (queried.Name != name || queried.PointsCost != pointsCost
|
|
|| queried.TotalCount != totalCount || queried.RemainingCount != totalCount)
|
|
return false;
|
|
|
|
// 更新
|
|
var newName = name + "_v2";
|
|
var newPointsCost = pointsCost + 10;
|
|
queried.Name = newName;
|
|
queried.PointsCost = newPointsCost;
|
|
queried.CouponType = "discount";
|
|
queried.DiscountAmount = 20m;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证更新
|
|
var updated = db.CouponTemplates.Find(template.Id)!;
|
|
return updated.Name == newName
|
|
&& updated.PointsCost == newPointsCost
|
|
&& updated.CouponType == "discount"
|
|
&& updated.DiscountAmount == 20m;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — 弹窗内容
|
|
/// 创建/更新后查询应得到与输入一致的结果
|
|
/// Validates: Requirements 18.3
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PopupContent_CrudRoundTrip_ShouldBeConsistent(NonEmptyString contentWrapper)
|
|
{
|
|
using var db = CreateDbContext();
|
|
var content = contentWrapper.Get;
|
|
|
|
// 创建
|
|
var popup = new PopupContent { Type = "verify-flow", Content = content };
|
|
db.PopupContents.Add(popup);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证创建
|
|
var queried = db.PopupContents.FirstOrDefault(p => p.Type == "verify-flow")!;
|
|
if (queried.Content != content)
|
|
return false;
|
|
|
|
// 更新
|
|
var newContent = content + "_updated";
|
|
queried.Content = newContent;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证更新
|
|
var updated = db.PopupContents.FirstOrDefault(p => p.Type == "verify-flow")!;
|
|
return updated.Content == newContent;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — 协议内容
|
|
/// 创建/更新后查询应得到与输入一致的结果
|
|
/// Validates: Requirements 18.11
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool Agreement_CrudRoundTrip_ShouldBeConsistent(NonEmptyString contentWrapper)
|
|
{
|
|
using var db = CreateDbContext();
|
|
var content = contentWrapper.Get;
|
|
|
|
// 创建
|
|
var agreement = new Agreement { Type = "user-agreement", Content = content };
|
|
db.Agreements.Add(agreement);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证创建
|
|
var queried = db.Agreements.FirstOrDefault(a => a.Type == "user-agreement")!;
|
|
if (queried.Content != content)
|
|
return false;
|
|
|
|
// 更新
|
|
var newContent = content + "_v2";
|
|
queried.Content = newContent;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证更新
|
|
var updated = db.Agreements.FirstOrDefault(a => a.Type == "user-agreement")!;
|
|
return updated.Content == newContent;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — 积分规则
|
|
/// 创建/更新后查询应得到与输入一致的结果
|
|
/// Validates: Requirements 18.10
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PointsRule_CrudRoundTrip_ShouldBeConsistent(
|
|
PositiveInt chargeWrapper, PositiveInt pointsWrapper)
|
|
{
|
|
using var db = CreateDbContext();
|
|
var chargeAmount = (decimal)(chargeWrapper.Get % 1000 + 1);
|
|
var pointsValue = pointsWrapper.Get % 500 + 1;
|
|
|
|
// 创建
|
|
var rule = new PointsRule
|
|
{
|
|
ChargeAmount = chargeAmount,
|
|
PointsValue = pointsValue,
|
|
IsActive = true,
|
|
};
|
|
db.PointsRules.Add(rule);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证创建
|
|
var queried = db.PointsRules.Find(rule.Id)!;
|
|
if (queried.ChargeAmount != chargeAmount || queried.PointsValue != pointsValue)
|
|
return false;
|
|
|
|
// 更新
|
|
var newCharge = chargeAmount + 10;
|
|
var newPoints = pointsValue + 5;
|
|
queried.ChargeAmount = newCharge;
|
|
queried.PointsValue = newPoints;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证更新
|
|
var updated = db.PointsRules.Find(rule.Id)!;
|
|
return updated.ChargeAmount == newCharge && updated.PointsValue == newPoints;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Feature: huangyan-parking-points, Property 20: 管理后台CRUD Round-Trip — 商户员工
|
|
/// 绑定/解绑后查询应得到一致的结果
|
|
/// Validates: Requirements 18.5
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool Merchant_BindUnbind_ShouldBeConsistent(PositiveInt storeIdSeed)
|
|
{
|
|
using var db = CreateDbContext();
|
|
|
|
// 创建门店
|
|
var store = new Store { Name = "测试门店", Type = "human" };
|
|
db.Stores.Add(store);
|
|
db.SaveChanges();
|
|
|
|
// 创建用户并绑定为商户
|
|
var user = new User
|
|
{
|
|
Uid = "123456",
|
|
Phone = "13800001111",
|
|
IsMerchant = true,
|
|
StoreId = store.Id,
|
|
};
|
|
db.Users.Add(user);
|
|
db.SaveChanges();
|
|
|
|
// 查询验证绑定
|
|
var queried = db.Users.Find(user.Id)!;
|
|
if (!queried.IsMerchant || queried.StoreId != store.Id)
|
|
return false;
|
|
|
|
// 解绑
|
|
queried.IsMerchant = false;
|
|
queried.StoreId = null;
|
|
db.SaveChanges();
|
|
|
|
// 查询验证解绑
|
|
var updated = db.Users.Find(user.Id)!;
|
|
return !updated.IsMerchant && updated.StoreId == null;
|
|
}
|
|
}
|