Files
Rogee 7fcabe0225
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
first commit
2025-09-28 10:05:07 +08:00

798 lines
21 KiB
Go
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.
package testing
import (
"encoding/json"
"fmt"
"time"
)
// TestStatus 定义测试状态
type TestStatus int
const (
PENDING TestStatus = iota
RUNNING
PASSED
FAILED
SKIPPED
TIMEOUT
)
// TestType 定义测试类型
type TestType int
const (
UNIT TestType = iota
INTEGRATION
CONTRACT
PERFORMANCE
SECURITY
LOAD
)
// TestPriority 定义测试优先级
type TestPriority int
const (
LOW TestPriority = iota
MEDIUM
HIGH
CRITICAL
)
// TestCase 表示测试用例的结构
// 该结构体包含测试用例的所有信息,包括输入、期望输出、执行状态等
type TestCase struct {
// 基本信息字段
ID string `json:"id" yaml:"id"`
Name string `json:"name" yaml:"name"`
Description string `json:"description" yaml:"description"`
Type TestType `json:"type" yaml:"type"`
Priority TestPriority `json:"priority" yaml:"priority"`
Category string `json:"category" yaml:"category"`
Subsystem string `json:"subsystem" yaml:"subsystem"`
Tags []string `json:"tags" yaml:"tags"`
// 测试数据字段
Input interface{} `json:"input" yaml:"input"`
Expectation interface{} `json:"expectation" yaml:"expectation"`
Config interface{} `json:"config" yaml:"config"`
Preconditions []string `json:"preconditions" yaml:"preconditions"`
Postconditions []string `json:"postconditions" yaml:"postconditions"`
// 执行信息字段
Status TestStatus `json:"status" yaml:"status"`
StartedAt time.Time `json:"started_at" yaml:"started_at"`
CompletedAt time.Time `json:"completed_at" yaml:"completed_at"`
Duration time.Duration `json:"duration" yaml:"duration"`
Attempts int `json:"attempts" yaml:"attempts"`
MaxAttempts int `json:"max_attempts" yaml:"max_attempts"`
Timeout time.Duration `json:"timeout" yaml:"timeout"`
// 结果字段
ActualResult interface{} `json:"actual_result" yaml:"actual_result"`
Error error `json:"error" yaml:"error"`
ErrorType string `json:"error_type" yaml:"error_type"`
ErrorDetail string `json:"error_detail" yaml:"error_detail"`
ErrorMessage string `json:"error_message" yaml:"error_message"`
// 依赖和排除字段
Dependencies []string `json:"dependencies" yaml:"dependencies"`
Exclusions []string `json:"exclusions" yaml:"exclusions"`
RunIf string `json:"run_if" yaml:"run_if"`
SkipIf string `json:"skip_if" yaml:"skip_if"`
// 性能指标字段
PerformanceMetrics map[string]interface{} `json:"performance_metrics" yaml:"performance_metrics"`
MemoryUsage int64 `json:"memory_usage" yaml:"memory_usage"`
CPUUsage float64 `json:"cpu_usage" yaml:"cpu_usage"`
Throughput float64 `json:"throughput" yaml:"throughput"`
// 元数据字段
CreatedBy string `json:"created_by" yaml:"created_by"`
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
UpdatedAt time.Time `json:"updated_at" yaml:"updated_at"`
Version string `json:"version" yaml:"version"`
Documentation string `json:"documentation" yaml:"documentation"`
// 自定义字段
Custom map[string]interface{} `json:"custom,omitempty" yaml:"custom,omitempty"`
Attachments []TestAttachment `json:"attachments,omitempty" yaml:"attachments,omitempty"`
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
}
// TestAttachment 测试附件
type TestAttachment struct {
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
Path string `json:"path" yaml:"path"`
Size int64 `json:"size" yaml:"size"`
Description string `json:"description" yaml:"description"`
}
// NewTestCase 创建新的测试用例
// 返回包含基本信息的TestCase结构体
func NewTestCase(id, name string, testType TestType) *TestCase {
now := time.Now()
return &TestCase{
ID: id,
Name: name,
Type: testType,
Priority: MEDIUM,
Status: PENDING,
Tags: make([]string, 0),
Preconditions: make([]string, 0),
Postconditions: make([]string, 0),
Dependencies: make([]string, 0),
Exclusions: make([]string, 0),
Attachments: make([]TestAttachment, 0),
MaxAttempts: 1,
CreatedAt: now,
UpdatedAt: now,
PerformanceMetrics: make(map[string]interface{}),
Custom: make(map[string]interface{}),
Parameters: make(map[string]interface{}),
}
}
// NewUnitTest 创建单元测试用例
// 返回配置好的单元测试用例实例
func NewUnitTest(id, name string) *TestCase {
return NewTestCase(id, name, UNIT).
SetCategory("unit").
SetSubsystem("core").
SetTimeout(30 * time.Second)
}
// NewIntegrationTest 创建集成测试用例
// 返回配置好的集成测试用例实例
func NewIntegrationTest(id, name string) *TestCase {
return NewTestCase(id, name, INTEGRATION).
SetCategory("integration").
SetSubsystem("system").
SetTimeout(120 * time.Second).
SetMaxAttempts(3)
}
// NewContractTest 创建契约测试用例
// 返回配置好的契约测试用例实例
func NewContractTest(id, name string) *TestCase {
return NewTestCase(id, name, CONTRACT).
SetCategory("contract").
SetSubsystem("api").
SetTimeout(60 * time.Second)
}
// NewPerformanceTest 创建性能测试用例
// 返回配置好的性能测试用例实例
func NewPerformanceTest(id, name string) *TestCase {
return NewTestCase(id, name, PERFORMANCE).
SetCategory("performance").
SetSubsystem("performance").
SetTimeout(300 * time.Second).
AddPerformanceMetric("max_response_time", 1000.0).
AddPerformanceMetric("max_memory_usage", 100*1024*1024) // 100MB
}
// SetInput 设置测试输入数据
// 返回更新后的TestCase实例
func (tc *TestCase) SetInput(input interface{}) *TestCase {
tc.Input = input
tc.UpdatedAt = time.Now()
return tc
}
// SetExpectation 设置测试期望结果
// 返回更新后的TestCase实例
func (tc *TestCase) SetExpectation(expectation interface{}) *TestCase {
tc.Expectation = expectation
tc.UpdatedAt = time.Now()
return tc
}
// SetConfig 设置测试配置
// 返回更新后的TestCase实例
func (tc *TestCase) SetConfig(config interface{}) *TestCase {
tc.Config = config
tc.UpdatedAt = time.Now()
return tc
}
// AddPrecondition 添加前置条件
// 返回更新后的TestCase实例
func (tc *TestCase) AddPrecondition(condition string) *TestCase {
tc.Preconditions = append(tc.Preconditions, condition)
tc.UpdatedAt = time.Now()
return tc
}
// AddPostcondition 添加后置条件
// 返回更新后的TestCase实例
func (tc *TestCase) AddPostcondition(condition string) *TestCase {
tc.Postconditions = append(tc.Postconditions, condition)
tc.UpdatedAt = time.Now()
return tc
}
// AddTag 添加标签
// 返回更新后的TestCase实例
func (tc *TestCase) AddTag(tag string) *TestCase {
tc.Tags = append(tc.Tags, tag)
tc.UpdatedAt = time.Now()
return tc
}
// AddTags 添加多个标签
// 返回更新后的TestCase实例
func (tc *TestCase) AddTags(tags ...string) *TestCase {
tc.Tags = append(tc.Tags, tags...)
tc.UpdatedAt = time.Now()
return tc
}
// AddDependency 添加依赖测试
// 返回更新后的TestCase实例
func (tc *TestCase) AddDependency(dependency string) *TestCase {
tc.Dependencies = append(tc.Dependencies, dependency)
tc.UpdatedAt = time.Now()
return tc
}
// AddExclusion 添加排除条件
// 返回更新后的TestCase实例
func (tc *TestCase) AddExclusion(exclusion string) *TestCase {
tc.Exclusions = append(tc.Exclusions, exclusion)
tc.UpdatedAt = time.Now()
return tc
}
// SetPriority 设置优先级
// 返回更新后的TestCase实例
func (tc *TestCase) SetPriority(priority TestPriority) *TestCase {
tc.Priority = priority
tc.UpdatedAt = time.Now()
return tc
}
// SetTimeout 设置超时时间
// 返回更新后的TestCase实例
func (tc *TestCase) SetTimeout(timeout time.Duration) *TestCase {
tc.Timeout = timeout
tc.UpdatedAt = time.Now()
return tc
}
// SetMaxAttempts 设置最大重试次数
// 返回更新后的TestCase实例
func (tc *TestCase) SetMaxAttempts(maxAttempts int) *TestCase {
tc.MaxAttempts = maxAttempts
tc.UpdatedAt = time.Now()
return tc
}
// SetCategory 设置分类
// 返回更新后的TestCase实例
func (tc *TestCase) SetCategory(category string) *TestCase {
tc.Category = category
tc.UpdatedAt = time.Now()
return tc
}
// SetSubsystem 设置子系统
// 返回更新后的TestCase实例
func (tc *TestCase) SetSubsystem(subsystem string) *TestCase {
tc.Subsystem = subsystem
tc.UpdatedAt = time.Now()
return tc
}
// SetDescription 设置描述
// 返回更新后的TestCase实例
func (tc *TestCase) SetDescription(description string) *TestCase {
tc.Description = description
tc.UpdatedAt = time.Now()
return tc
}
// SetRunIf 设置运行条件
// 返回更新后的TestCase实例
func (tc *TestCase) SetRunIf(runIf string) *TestCase {
tc.RunIf = runIf
tc.UpdatedAt = time.Now()
return tc
}
// SetSkipIf 设置跳过条件
// 返回更新后的TestCase实例
func (tc *TestCase) SetSkipIf(skipIf string) *TestCase {
tc.SkipIf = skipIf
tc.UpdatedAt = time.Now()
return tc
}
// AddParameter 添加参数
// 返回更新后的TestCase实例
func (tc *TestCase) AddParameter(key string, value interface{}) *TestCase {
if tc.Parameters == nil {
tc.Parameters = make(map[string]interface{})
}
tc.Parameters[key] = value
tc.UpdatedAt = time.Now()
return tc
}
// AddPerformanceMetric 添加性能指标
// 返回更新后的TestCase实例
func (tc *TestCase) AddPerformanceMetric(key string, value interface{}) *TestCase {
if tc.PerformanceMetrics == nil {
tc.PerformanceMetrics = make(map[string]interface{})
}
tc.PerformanceMetrics[key] = value
tc.UpdatedAt = time.Now()
return tc
}
// AddCustom 添加自定义字段
// 返回更新后的TestCase实例
func (tc *TestCase) AddCustom(key string, value interface{}) *TestCase {
if tc.Custom == nil {
tc.Custom = make(map[string]interface{})
}
tc.Custom[key] = value
tc.UpdatedAt = time.Now()
return tc
}
// AddAttachment 添加附件
// 返回更新后的TestCase实例
func (tc *TestCase) AddAttachment(name, attachmentType, path string, size int64, description string) *TestCase {
tc.Attachments = append(tc.Attachments, TestAttachment{
Name: name,
Type: attachmentType,
Path: path,
Size: size,
Description: description,
})
tc.UpdatedAt = time.Now()
return tc
}
// Start 开始执行测试
// 标记测试为运行状态,记录开始时间
func (tc *TestCase) Start() {
tc.Status = RUNNING
tc.StartedAt = time.Now()
tc.Attempts++
tc.UpdatedAt = time.Now()
}
// Complete 完成测试执行
// 设置测试结果状态,记录完成时间和持续时间
func (tc *TestCase) Complete(success bool, actualResult interface{}, err error) {
tc.Status = PASSED
if !success {
tc.Status = FAILED
}
tc.CompletedAt = time.Now()
tc.Duration = tc.CompletedAt.Sub(tc.StartedAt)
tc.ActualResult = actualResult
tc.Error = err
if err != nil {
tc.ErrorType = fmt.Sprintf("%T", err)
tc.ErrorDetail = err.Error()
tc.ErrorMessage = err.Error()
}
tc.UpdatedAt = time.Now()
}
// Skip 跳过测试
// 标记测试为跳过状态,记录跳过原因
func (tc *TestCase) Skip(reason string) {
tc.Status = SKIPPED
tc.ErrorMessage = reason
tc.UpdatedAt = time.Now()
}
// MarkAsTimeout 测试超时
// 标记测试为超时状态
func (tc *TestCase) MarkAsTimeout() {
tc.Status = TIMEOUT
tc.CompletedAt = time.Now()
tc.Duration = tc.CompletedAt.Sub(tc.StartedAt)
tc.ErrorMessage = "Test execution timeout"
tc.UpdatedAt = time.Now()
}
// Validate 验证测试用例的有效性
// 返回error如果测试用例无效nil表示有效
func (tc *TestCase) Validate() error {
if tc.ID == "" {
return fmt.Errorf("test case ID cannot be empty")
}
if tc.Name == "" {
return fmt.Errorf("test case name cannot be empty")
}
if tc.Type < UNIT || tc.Type > LOAD {
return fmt.Errorf("invalid test type: %d", tc.Type)
}
if tc.Priority < LOW || tc.Priority > CRITICAL {
return fmt.Errorf("invalid test priority: %d", tc.Priority)
}
if tc.Timeout <= 0 {
return fmt.Errorf("timeout must be positive, got: %v", tc.Timeout)
}
if tc.MaxAttempts <= 0 {
return fmt.Errorf("max attempts must be positive, got: %d", tc.MaxAttempts)
}
if tc.Input == nil {
return fmt.Errorf("test input cannot be nil")
}
if tc.Expectation == nil {
return fmt.Errorf("test expectation cannot be nil")
}
return nil
}
// ShouldRun 判断是否应该运行测试
// 根据运行条件和跳过条件判断
func (tc *TestCase) ShouldRun() bool {
// 如果已经有最终状态,不再运行
if tc.Status == PASSED || tc.Status == FAILED || tc.Status == SKIPPED || tc.Status == TIMEOUT {
return false
}
// 如果超过最大尝试次数,不再运行
if tc.Attempts >= tc.MaxAttempts {
return false
}
// 这里可以实现更复杂的条件判断逻辑
// 例如RunIf 和 SkipIf 条件的表达式解析
return true
}
// IsReady 检查测试是否准备好运行
// 检查所有前置条件是否满足
func (tc *TestCase) IsReady() bool {
// 这里可以实现前置条件检查逻辑
// 例如:检查依赖项是否完成,环境是否准备就绪等
return true
}
// HasDependency 检查是否有指定依赖
// 返回true如果包含指定依赖
func (tc *TestCase) HasDependency(dependency string) bool {
for _, dep := range tc.Dependencies {
if dep == dependency {
return true
}
}
return false
}
// HasTag 检查是否有指定标签
// 返回true如果包含指定标签
func (tc *TestCase) HasTag(tag string) bool {
for _, t := range tc.Tags {
if t == tag {
return true
}
}
return false
}
// IsSuccessful 检查测试是否成功
// 返回true如果测试成功通过
func (tc *TestCase) IsSuccessful() bool {
return tc.Status == PASSED
}
// IsFailed 检查测试是否失败
// 返回true如果测试执行失败
func (tc *TestCase) IsFailed() bool {
return tc.Status == FAILED
}
// IsSkipped 检查测试是否跳过
// 返回true如果测试被跳过
func (tc *TestCase) IsSkipped() bool {
return tc.Status == SKIPPED
}
// IsTimeout 检查测试是否超时
// 返回true如果测试执行超时
func (tc *TestCase) IsTimeout() bool {
return tc.Status == TIMEOUT
}
// IsRunning 检查测试是否正在运行
// 返回true如果测试正在执行
func (tc *TestCase) IsRunning() bool {
return tc.Status == RUNNING
}
// GetDuration 获取执行持续时间
// 返回测试执行的持续时间
func (tc *TestCase) GetDuration() time.Duration {
if tc.StartedAt.IsZero() {
return 0
}
if tc.CompletedAt.IsZero() {
return time.Since(tc.StartedAt)
}
return tc.Duration
}
// GetPerformanceMetric 获取性能指标
// 返回指定指标的值和是否存在
func (tc *TestCase) GetPerformanceMetric(key string) (interface{}, bool) {
value, exists := tc.PerformanceMetrics[key]
return value, exists
}
// GetParameter 获取参数值
// 返回指定参数的值和是否存在
func (tc *TestCase) GetParameter(key string) (interface{}, bool) {
value, exists := tc.Parameters[key]
return value, exists
}
// GetCustom 获取自定义字段值
// 返回指定自定义字段的值和是否存在
func (tc *TestCase) GetCustom(key string) (interface{}, bool) {
value, exists := tc.Custom[key]
return value, exists
}
// Clone 创建测试用例的副本
// 返回新的TestCase实例深拷贝所有字段
func (tc *TestCase) Clone() *TestCase {
clone := &TestCase{
ID: tc.ID + "_clone",
Name: tc.Name,
Description: tc.Description,
Type: tc.Type,
Priority: tc.Priority,
Category: tc.Category,
Subsystem: tc.Subsystem,
Status: PENDING,
MaxAttempts: tc.MaxAttempts,
Timeout: tc.Timeout,
Input: tc.Input,
Expectation: tc.Expectation,
Config: tc.Config,
RunIf: tc.RunIf,
SkipIf: tc.SkipIf,
CreatedBy: tc.CreatedBy,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Version: tc.Version,
Documentation: tc.Documentation,
}
// 深拷贝切片
if len(tc.Tags) > 0 {
clone.Tags = make([]string, len(tc.Tags))
copy(clone.Tags, tc.Tags)
}
if len(tc.Preconditions) > 0 {
clone.Preconditions = make([]string, len(tc.Preconditions))
copy(clone.Preconditions, tc.Preconditions)
}
if len(tc.Postconditions) > 0 {
clone.Postconditions = make([]string, len(tc.Postconditions))
copy(clone.Postconditions, tc.Postconditions)
}
if len(tc.Dependencies) > 0 {
clone.Dependencies = make([]string, len(tc.Dependencies))
copy(clone.Dependencies, tc.Dependencies)
}
if len(tc.Exclusions) > 0 {
clone.Exclusions = make([]string, len(tc.Exclusions))
copy(clone.Exclusions, tc.Exclusions)
}
if len(tc.Attachments) > 0 {
clone.Attachments = make([]TestAttachment, len(tc.Attachments))
copy(clone.Attachments, tc.Attachments)
}
// 深拷贝映射
if len(tc.PerformanceMetrics) > 0 {
clone.PerformanceMetrics = make(map[string]interface{})
for k, v := range tc.PerformanceMetrics {
clone.PerformanceMetrics[k] = v
}
}
if len(tc.Parameters) > 0 {
clone.Parameters = make(map[string]interface{})
for k, v := range tc.Parameters {
clone.Parameters[k] = v
}
}
if len(tc.Custom) > 0 {
clone.Custom = make(map[string]interface{})
for k, v := range tc.Custom {
clone.Custom[k] = v
}
}
return clone
}
// ToJSON 将测试用例转换为JSON格式
// 返回JSON格式的测试用例字符串
func (tc *TestCase) ToJSON() (string, error) {
if err := tc.Validate(); err != nil {
return "", fmt.Errorf("test case validation failed: %v", err)
}
data, err := json.Marshal(tc)
if err != nil {
return "", fmt.Errorf("failed to marshal test case: %v", err)
}
return string(data), nil
}
// ToJSONBytes 将测试用例转换为JSON字节数组
// 返回JSON格式的测试用例字节数组
func (tc *TestCase) ToJSONBytes() ([]byte, error) {
if err := tc.Validate(); err != nil {
return nil, fmt.Errorf("test case validation failed: %v", err)
}
return json.Marshal(tc)
}
// FromJSON 从JSON字符串解析测试用例
// 解析JSON字符串到TestCase
func (tc *TestCase) FromJSON(jsonStr string) error {
return json.Unmarshal([]byte(jsonStr), tc)
}
// FromJSONBytes 从JSON字节数组解析测试用例
// 解析JSON字节数组到TestCase
func (tc *TestCase) FromJSONBytes(data []byte) error {
return json.Unmarshal(data, tc)
}
// ToYAML 将测试用例转换为YAML格式
// 返回YAML格式的测试用例字符串
func (tc *TestCase) ToYAML() (string, error) {
if err := tc.Validate(); err != nil {
return "", fmt.Errorf("test case validation failed: %v", err)
}
// 这里可以使用 yaml.Marshal但为了保持简单暂时使用JSON格式
// 在实际项目中,应该引入 yaml 包
return tc.ToJSON()
}
// String 返回测试用例的字符串表示
// 实现Stringer接口
func (tc *TestCase) String() string {
return fmt.Sprintf("TestCase[%s:%s] - %s", tc.ID, tc.GetTypeString(), tc.Name)
}
// GetTypeString 获取测试类型的字符串表示
// 返回测试类型的字符串
func (tc *TestCase) GetTypeString() string {
switch tc.Type {
case UNIT:
return "UNIT"
case INTEGRATION:
return "INTEGRATION"
case CONTRACT:
return "CONTRACT"
case PERFORMANCE:
return "PERFORMANCE"
case SECURITY:
return "SECURITY"
case LOAD:
return "LOAD"
default:
return "UNKNOWN"
}
}
// GetPriorityString 获取优先级的字符串表示
// 返回优先级的字符串
func (tc *TestCase) GetPriorityString() string {
switch tc.Priority {
case LOW:
return "LOW"
case MEDIUM:
return "MEDIUM"
case HIGH:
return "HIGH"
case CRITICAL:
return "CRITICAL"
default:
return "UNKNOWN"
}
}
// GetStatusString 获取状态的字符串表示
// 返回状态的字符串
func (tc *TestCase) GetStatusString() string {
switch tc.Status {
case PENDING:
return "PENDING"
case RUNNING:
return "RUNNING"
case PASSED:
return "PASSED"
case FAILED:
return "FAILED"
case SKIPPED:
return "SKIPPED"
case TIMEOUT:
return "TIMEOUT"
default:
return "UNKNOWN"
}
}
// Reset 重置测试用例状态
// 重置执行相关的字段,保留配置信息
func (tc *TestCase) Reset() {
tc.Status = PENDING
tc.StartedAt = time.Time{}
tc.CompletedAt = time.Time{}
tc.Duration = 0
tc.Attempts = 0
tc.ActualResult = nil
tc.Error = nil
tc.ErrorType = ""
tc.ErrorDetail = ""
tc.ErrorMessage = ""
tc.MemoryUsage = 0
tc.CPUUsage = 0
tc.Throughput = 0
tc.UpdatedAt = time.Now()
}
// MarkAsPassed 标记测试为通过
// 快速标记测试为成功状态
func (tc *TestCase) MarkAsPassed() {
tc.Status = PASSED
tc.CompletedAt = time.Now()
if !tc.StartedAt.IsZero() {
tc.Duration = tc.CompletedAt.Sub(tc.StartedAt)
}
tc.UpdatedAt = time.Now()
}
// MarkAsFailed 标记测试为失败
// 快速标记测试为失败状态,可指定错误信息
func (tc *TestCase) MarkAsFailed(err error) {
tc.Status = FAILED
tc.Error = err
if err != nil {
tc.ErrorType = fmt.Sprintf("%T", err)
tc.ErrorDetail = err.Error()
tc.ErrorMessage = err.Error()
}
tc.CompletedAt = time.Now()
if !tc.StartedAt.IsZero() {
tc.Duration = tc.CompletedAt.Sub(tc.StartedAt)
}
tc.UpdatedAt = time.Now()
}