Files
tiku-backend.net/Tiku.IntegrationTests/Api/QuestionBankEndpointTests.cs
2026-07-26 14:17:30 +08:00

203 lines
7.1 KiB
C#

using System.Net;
using System.Text.Json;
using Tiku.Domain.Common;
using Tiku.Domain.Content;
using Tiku.Domain.QuestionBanks;
using Tiku.Domain.Tenancy;
namespace Tiku.IntegrationTests.Api;
public sealed class QuestionBankEndpointTests
{
[Fact]
public async Task Question_banks_return_active_tenant_banks_only()
{
var tenantId = Guid.NewGuid();
var otherTenantId = Guid.NewGuid();
await using var factory = new ApiTestFactory();
await factory.SeedAsync(
Tenant(tenantId, "master"),
Tenant(otherTenantId, "other"),
new QuestionBank
{
Id = Guid.NewGuid(),
TenantId = tenantId,
Name = "A 题库",
Status = QuestionBankStatus.Active
},
new QuestionBank
{
Id = Guid.NewGuid(),
TenantId = tenantId,
Name = "归档题库",
Status = QuestionBankStatus.Archived
},
new QuestionBank
{
Id = Guid.NewGuid(),
TenantId = otherTenantId,
Name = "其他租户题库",
Status = QuestionBankStatus.Active
});
using var client = factory.CreateClient();
using var response = await client.GetAsync("/api/catalog/question-banks?tenantCode=master");
var items = await ReadItemsAsync(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("A 题库", Assert.Single(items).GetProperty("name").GetString());
}
[Fact]
public async Task Questions_support_filters_and_current_version_projection()
{
var tenantId = Guid.NewGuid();
var bankId = Guid.NewGuid();
var subjectId = Guid.NewGuid();
var categoryId = Guid.NewGuid();
var collectionId = Guid.NewGuid();
var includedQuestionId = Guid.NewGuid();
var excludedQuestionId = Guid.NewGuid();
var versionId = Guid.NewGuid();
await using var factory = new ApiTestFactory();
await factory.SeedAsync(
Tenant(tenantId, "master"),
new QuestionBank { Id = bankId, TenantId = tenantId, Name = "题库" },
new QuestionCollection { Id = collectionId, TenantId = tenantId, Name = "题集", Status = ContentStatus.Active },
new Question
{
Id = includedQuestionId,
TenantId = tenantId,
QuestionBankId = bankId,
SubjectId = subjectId,
CategoryId = categoryId,
Type = "choice",
TypeLabel = "单选题",
Difficulty = 2,
Status = QuestionStatus.Published,
CurrentVersionId = versionId
},
new QuestionVersion
{
Id = versionId,
TenantId = tenantId,
QuestionId = includedQuestionId,
VersionNo = 2,
Content = "题干关键词"
},
new QuestionCollectionItem
{
Id = Guid.NewGuid(),
TenantId = tenantId,
CollectionId = collectionId,
QuestionId = includedQuestionId
},
new Question
{
Id = excludedQuestionId,
TenantId = tenantId,
QuestionBankId = bankId,
SubjectId = subjectId,
Type = "choice",
Status = QuestionStatus.Archived
});
using var client = factory.CreateClient();
using var response = await client.GetAsync(
$"/api/catalog/questions?tenantCode=master&questionBankId={bankId}&subjectId={subjectId}&categoryId={categoryId}&collectionId={collectionId}&type=choice&keyword=关键词");
var items = await ReadItemsAsync(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var item = Assert.Single(items);
Assert.Equal(includedQuestionId, item.GetProperty("id").GetGuid());
Assert.Equal(versionId, item.GetProperty("versionId").GetGuid());
Assert.Equal("题干关键词", item.GetProperty("content").GetString());
}
[Fact]
public async Task Question_detail_returns_not_found_for_archived_question()
{
var tenantId = Guid.NewGuid();
var questionId = Guid.NewGuid();
await using var factory = new ApiTestFactory();
await factory.SeedAsync(
Tenant(tenantId, "master"),
new Question
{
Id = questionId,
TenantId = tenantId,
Type = "choice",
Status = QuestionStatus.Archived
});
using var client = factory.CreateClient();
using var response = await client.GetAsync($"/api/catalog/questions/{questionId}?tenantCode=master");
var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.Equal("question_not_found", body.RootElement.GetProperty("code").GetString());
}
[Fact]
public async Task Question_versions_are_returned_newest_first()
{
var tenantId = Guid.NewGuid();
var questionId = Guid.NewGuid();
await using var factory = new ApiTestFactory();
await factory.SeedAsync(
Tenant(tenantId, "master"),
new Question
{
Id = questionId,
TenantId = tenantId,
Type = "choice",
Status = QuestionStatus.Published
},
new QuestionVersion
{
Id = Guid.NewGuid(),
TenantId = tenantId,
QuestionId = questionId,
VersionNo = 1,
Content = "旧版本"
},
new QuestionVersion
{
Id = Guid.NewGuid(),
TenantId = tenantId,
QuestionId = questionId,
VersionNo = 2,
Content = "新版本"
});
using var client = factory.CreateClient();
using var response = await client.GetAsync($"/api/catalog/questions/{questionId}/versions?tenantCode=master");
var items = await ReadItemsAsync(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(["新版本", "旧版本"], items.Select(item => item.GetProperty("content").GetString()!).ToArray());
}
private static Tenant Tenant(Guid id, string slug)
{
return new Tenant
{
Id = id,
Slug = slug,
Name = slug,
Status = TenantStatus.Active,
Metadata = JsonDefaults.Object()
};
}
private static async Task<JsonElement[]> ReadItemsAsync(HttpResponseMessage response)
{
var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
return body.RootElement
.GetProperty("items")
.EnumerateArray()
.Select(item => item.Clone())
.ToArray();
}
}