868 lines
22 KiB
C#
868 lines
22 KiB
C#
using Common.Results;
|
|
using Common.ExpandException;
|
|
|
|
namespace Common.Test;
|
|
|
|
/// <summary>
|
|
/// Result 模式测试
|
|
/// 展示函数式错误处理的所有功能
|
|
/// </summary>
|
|
[TestClass]
|
|
public class ResultTests
|
|
{
|
|
#region 基础创建和状态测试
|
|
|
|
/// <summary>
|
|
/// 测试:创建成功的 Result
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Success_CreatesSuccessResult()
|
|
{
|
|
// Act: 创建成功的无返回值 Result
|
|
var result = Result.Success();
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
Assert.IsFalse(result.IsFailure);
|
|
Assert.IsNull(result.Exception);
|
|
Assert.IsNull(result.ErrorMessage);
|
|
Assert.IsNull(result.ErrorCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:创建成功的 Result<T>
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Success_WithValue_CreatesSuccessResultWithValue()
|
|
{
|
|
// Act: 创建带值的成功 Result
|
|
var result = Result.Success(42);
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
Assert.AreEqual(42, result.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:创建失败的 Result(使用错误消息)
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Failure_WithMessage_CreatesFailureResult()
|
|
{
|
|
// Act
|
|
var result = Result.Failure<int>("Something went wrong");
|
|
|
|
// Assert
|
|
Assert.IsFalse(result.IsSuccess);
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.AreEqual("Something went wrong", result.ErrorMessage);
|
|
Assert.IsNull(result.ErrorCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:创建失败的 Result(使用异常)
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Failure_WithException_CreatesFailureResult()
|
|
{
|
|
// Arrange
|
|
var exception = new InvalidOperationException("Invalid operation");
|
|
|
|
// Act
|
|
var result = Result.Failure<int>(exception);
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.AreSame(exception, result.Exception);
|
|
Assert.AreEqual("Invalid operation", result.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:创建带错误码的失败 Result
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Failure_WithErrorCode_CreatesFailureResultWithCode()
|
|
{
|
|
// Act
|
|
var result = Result.Failure<int>(404L, "Not found");
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.AreEqual(404L, result.ErrorCode);
|
|
Assert.AreEqual("Not found", result.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:从 ExceptionExpand 创建失败 Result
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Failure_WithExceptionExpand_ExtractsErrorCode()
|
|
{
|
|
// Arrange
|
|
var exception = new ExceptionExpand(1001L, "Custom error", "Try again");
|
|
|
|
// Act
|
|
var result = Result.Failure<int>(exception);
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.AreEqual(1001L, result.ErrorCode);
|
|
Assert.AreEqual("Custom error", result.ErrorMessage);
|
|
Assert.AreSame(exception, result.Exception);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Try 模式测试
|
|
|
|
/// <summary>
|
|
/// 测试:Try 捕获成功的操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Try_SuccessfulAction_ReturnsSuccess()
|
|
{
|
|
// Arrange
|
|
var executed = false;
|
|
|
|
// Act
|
|
var result = Result.Try(() => { executed = true; });
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
Assert.IsTrue(executed);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Try 捕获失败的操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Try_FailingAction_ReturnsFailure()
|
|
{
|
|
// Act
|
|
var result = Result.Try(() => { throw new InvalidOperationException("Operation failed"); });
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.IsInstanceOfType(result.Exception, typeof(InvalidOperationException));
|
|
Assert.AreEqual("Operation failed", result.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Try 捕获返回值的成功操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Try_SuccessfulFunc_ReturnsSuccessWithValue()
|
|
{
|
|
// Act
|
|
var result = Result.Try(() => int.Parse("123"));
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
Assert.AreEqual(123, result.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Try 捕获返回值的失败操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Try_FailingFunc_ReturnsFailure()
|
|
{
|
|
// Act
|
|
var result = Result.Try(() => int.Parse("invalid"));
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.IsInstanceOfType(result.Exception, typeof(FormatException));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:TryAsync 异步操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public async Task TryAsync_SuccessfulTask_ReturnsSuccess()
|
|
{
|
|
// Act
|
|
var result = await Result.TryAsync(async () => { await Task.Delay(10); });
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:TryAsync 异步操作返回值
|
|
/// </summary>
|
|
[TestMethod]
|
|
public async Task TryAsync_SuccessfulTaskWithValue_ReturnsSuccessWithValue()
|
|
{
|
|
// Act
|
|
var result = await Result.TryAsync(async () =>
|
|
{
|
|
await Task.Delay(10);
|
|
return 42;
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
Assert.AreEqual(42, result.Value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 值提取测试
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrNull 获取引用类型
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrNull_SuccessResult_ReturnsValue()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success("test");
|
|
|
|
// Act
|
|
var value = result.GetOrNull();
|
|
|
|
// Assert
|
|
Assert.AreEqual("test", value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrNull 失败返回 null
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrNull_FailureResult_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<string>("error");
|
|
|
|
// Act
|
|
var value = result.GetOrNull();
|
|
|
|
// Assert
|
|
Assert.IsNull(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrNullable 获取值类型
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrNullable_SuccessResult_ReturnsValue()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(42);
|
|
|
|
// Act
|
|
var value = result.GetOrNullable();
|
|
|
|
// Assert
|
|
Assert.AreEqual(42, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrDefault 获取默认值
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrDefault_FailureResult_ReturnsDefault()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>("error");
|
|
|
|
// Act
|
|
var value = result.GetOrDefault(999);
|
|
|
|
// Assert
|
|
Assert.AreEqual(999, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrThrow 成功时返回值
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrThrow_SuccessResult_ReturnsValue()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(42);
|
|
|
|
// Act
|
|
var value = result.GetOrThrow();
|
|
|
|
// Assert
|
|
Assert.AreEqual(42, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrThrow 失败时抛出异常
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrThrow_FailureResult_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var exception = new InvalidOperationException("test error");
|
|
var result = Result.Failure<int>(exception);
|
|
|
|
// Act & Assert
|
|
var thrown = Assert.ThrowsException<InvalidOperationException>(() => { result.GetOrThrow(); });
|
|
|
|
Assert.AreSame(exception, thrown);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetOrElse 使用函数提供替代值
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetOrElse_FailureResult_CallsAlternativeProvider()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>("error");
|
|
|
|
// Act
|
|
var value = result.GetOrElse(() => 100);
|
|
|
|
// Assert
|
|
Assert.AreEqual(100, value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 函数式操作测试
|
|
|
|
/// <summary>
|
|
/// 测试:Map 转换成功的值
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Map_SuccessResult_TransformsValue()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(10);
|
|
|
|
// Act
|
|
var mapped = result.Map(x => x * 2);
|
|
|
|
// Assert
|
|
Assert.IsTrue(mapped.IsSuccess);
|
|
Assert.AreEqual(20, mapped.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Map 传播失败
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Map_FailureResult_PropagatesFailure()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>("error");
|
|
|
|
// Act
|
|
var mapped = result.Map(x => x * 2);
|
|
|
|
// Assert
|
|
Assert.IsTrue(mapped.IsFailure);
|
|
Assert.AreEqual("error", mapped.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Bind 链式操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Bind_SuccessResult_ChainsOperations()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(10);
|
|
|
|
// Act
|
|
var bound = result
|
|
.Bind(x => x > 5 ? Result.Success(x * 2) : Result.Failure<int>("Too small"))
|
|
.Bind(x => Result.Success(x.ToString()));
|
|
|
|
// Assert
|
|
Assert.IsTrue(bound.IsSuccess);
|
|
Assert.AreEqual("20", bound.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Bind 中断失败链
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Bind_FailureInChain_StopsExecution()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(3);
|
|
var secondBindExecuted = false;
|
|
|
|
// Act
|
|
var bound = result
|
|
.Bind(x => x > 5 ? Result.Success(x * 2) : Result.Failure<int>("Too small"))
|
|
.Bind(x =>
|
|
{
|
|
secondBindExecuted = true;
|
|
return Result.Success(x * 2);
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(bound.IsFailure);
|
|
Assert.IsFalse(secondBindExecuted); // 第二个 Bind 不应该执行
|
|
Assert.AreEqual("Too small", bound.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Where 过滤值
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Where_PredicateSatisfied_ReturnsSuccess()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(10);
|
|
|
|
// Act
|
|
var filtered = result.Where(x => x > 5, "Value must be greater than 5");
|
|
|
|
// Assert
|
|
Assert.IsTrue(filtered.IsSuccess);
|
|
Assert.AreEqual(10, filtered.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Where 过滤失败
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Where_PredicateNotSatisfied_ReturnsFailure()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(3);
|
|
|
|
// Act
|
|
var filtered = result.Where(x => x > 5, "Value must be greater than 5");
|
|
|
|
// Assert
|
|
Assert.IsTrue(filtered.IsFailure);
|
|
Assert.AreEqual("Value must be greater than 5", filtered.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Ensure 验证
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Ensure_ValidationPasses_ReturnsSuccess()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success("test@example.com");
|
|
|
|
// Act
|
|
var ensured = result
|
|
.Ensure(email => email.Contains("@"), "Invalid email format")
|
|
.Ensure(email => email.Length > 5, "Email too short");
|
|
|
|
// Assert
|
|
Assert.IsTrue(ensured.IsSuccess);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Ensure 验证失败
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Ensure_ValidationFails_ReturnsFailure()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success("invalid");
|
|
|
|
// Act
|
|
var ensured = result.Ensure(email => email.Contains("@"), "Invalid email format");
|
|
|
|
// Assert
|
|
Assert.IsTrue(ensured.IsFailure);
|
|
Assert.AreEqual("Invalid email format", ensured.ErrorMessage);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 条件执行测试
|
|
|
|
/// <summary>
|
|
/// 测试:OnSuccess 成功时执行
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void OnSuccess_SuccessResult_ExecutesAction()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(42);
|
|
var executed = false;
|
|
var capturedValue = 0;
|
|
|
|
// Act
|
|
result.OnSuccess(value =>
|
|
{
|
|
executed = true;
|
|
capturedValue = value;
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(executed);
|
|
Assert.AreEqual(42, capturedValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:OnSuccess 失败时不执行
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void OnSuccess_FailureResult_DoesNotExecute()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>("error");
|
|
var executed = false;
|
|
|
|
// Act
|
|
result.OnSuccess(value => executed = true);
|
|
|
|
// Assert
|
|
Assert.IsFalse(executed);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:OnFailure 失败时执行
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void OnFailure_FailureResult_ExecutesAction()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>(404L, "Not found");
|
|
var executed = false;
|
|
string? capturedMessage = null;
|
|
long? capturedCode = null;
|
|
|
|
// Act
|
|
result.OnFailure((ex, msg, code) =>
|
|
{
|
|
executed = true;
|
|
capturedMessage = msg;
|
|
capturedCode = code;
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(executed);
|
|
Assert.AreEqual("Not found", capturedMessage);
|
|
Assert.AreEqual(404L, capturedCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Match 模式匹配
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Match_SuccessResult_CallsSuccessHandler()
|
|
{
|
|
// Arrange
|
|
var result = Result.Success(42);
|
|
|
|
// Act
|
|
var message = result.Match(
|
|
value => $"Success: {value}",
|
|
(ex, msg) => $"Error: {msg}"
|
|
);
|
|
|
|
// Assert
|
|
Assert.AreEqual("Success: 42", message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:Match 失败结果
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Match_FailureResult_CallsFailureHandler()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>("Something went wrong");
|
|
|
|
// Act
|
|
var message = result.Match(
|
|
value => $"Success: {value}",
|
|
(ex, msg) => $"Error: {msg}"
|
|
);
|
|
|
|
// Assert
|
|
Assert.AreEqual("Error: Something went wrong", message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LINQ 查询语法测试
|
|
|
|
/// <summary>
|
|
/// 测试:使用 LINQ 查询语法组合 Result
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void LinqQuery_CombinesResults()
|
|
{
|
|
// Arrange
|
|
var result1 = Result.Success(5);
|
|
var result2 = Result.Success(10);
|
|
|
|
// Act: 使用 LINQ 查询语法
|
|
var combined = from x in result1
|
|
from y in result2
|
|
where x > 0 && y > 0
|
|
select x + y;
|
|
|
|
// Assert
|
|
Assert.IsTrue(combined.IsSuccess);
|
|
Assert.AreEqual(15, combined.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:LINQ 查询中的失败传播
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void LinqQuery_PropagatesFailure()
|
|
{
|
|
// Arrange
|
|
var result1 = Result.Success(5);
|
|
var result2 = Result.Failure<int>("Error in result2");
|
|
|
|
// Act
|
|
var combined = from x in result1
|
|
from y in result2
|
|
select x + y;
|
|
|
|
// Assert
|
|
Assert.IsTrue(combined.IsFailure);
|
|
Assert.AreEqual("Error in result2", combined.ErrorMessage);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 错误码相关测试
|
|
|
|
/// <summary>
|
|
/// 测试:HasErrorCode 检查错误码
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void HasErrorCode_MatchingCode_ReturnsTrue()
|
|
{
|
|
// Arrange
|
|
var result = Result.Failure<int>(404L, "Not found");
|
|
|
|
// Act & Assert
|
|
Assert.IsTrue(result.HasErrorCode(404L));
|
|
Assert.IsFalse(result.HasErrorCode(500L));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:GetErrorCodeOrDefault 获取错误码
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GetErrorCodeOrDefault_ReturnsCodeOrDefault()
|
|
{
|
|
// Arrange
|
|
var failureResult = Result.Failure<int>(404L, "Not found");
|
|
var successResult = Result.Success(42);
|
|
|
|
// Act & Assert
|
|
Assert.AreEqual(404L, failureResult.GetErrorCodeOrDefault());
|
|
Assert.AreEqual(-1L, successResult.GetErrorCodeOrDefault());
|
|
Assert.AreEqual(999L, successResult.GetErrorCodeOrDefault(999L));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:FromExceptionExpand 转换自定义异常
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void FromExceptionExpand_CreatesResultWithErrorCode()
|
|
{
|
|
// Arrange
|
|
var exception = new ExceptionExpand(1001L, "Business error", "Check input");
|
|
|
|
// Act
|
|
var result = ResultExtensions.FromExceptionExpand<string>(exception);
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsFailure);
|
|
Assert.AreEqual(1001L, result.ErrorCode);
|
|
Assert.AreEqual("Business error", result.ErrorMessage);
|
|
Assert.AreSame(exception, result.Exception);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 异步操作测试
|
|
|
|
/// <summary>
|
|
/// 测试:MapAsync 异步转换
|
|
/// </summary>
|
|
[TestMethod]
|
|
public async Task MapAsync_TransformsValueAsynchronously()
|
|
{
|
|
// Arrange
|
|
var result = Task.FromResult(Result.Success(10));
|
|
|
|
// Act
|
|
var mapped = await result.MapAsync(async value =>
|
|
{
|
|
await Task.Delay(10);
|
|
return value * 2;
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(mapped.IsSuccess);
|
|
Assert.AreEqual(20, mapped.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:BindAsync 异步链式操作
|
|
/// </summary>
|
|
[TestMethod]
|
|
public async Task BindAsync_ChainsAsynchronously()
|
|
{
|
|
// Arrange
|
|
var result = Task.FromResult(Result.Success(10));
|
|
|
|
// Act
|
|
var bound = await result.BindAsync(async value =>
|
|
{
|
|
await Task.Delay(10);
|
|
return value > 5 ? Result.Success(value * 2) : Result.Failure<int>("Too small");
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(bound.IsSuccess);
|
|
Assert.AreEqual(20, bound.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试:DoOnSuccessAsync 异步副作用
|
|
/// </summary>
|
|
[TestMethod]
|
|
public async Task DoOnSuccessAsync_ExecutesAsyncAction()
|
|
{
|
|
// Arrange
|
|
var result = Task.FromResult(Result.Success(42));
|
|
var executed = false;
|
|
|
|
// Act
|
|
await result.DoOnSuccessAsync(async value =>
|
|
{
|
|
await Task.Delay(10);
|
|
executed = true;
|
|
});
|
|
|
|
// Assert
|
|
Assert.IsTrue(executed);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 实际应用场景测试
|
|
|
|
/// <summary>
|
|
/// 场景测试:验证用户输入
|
|
/// 演示多步骤验证链
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Scenario_ValidateUserInput()
|
|
{
|
|
// Act: 验证有效输入
|
|
var validResult = ValidateEmail("user@example.com");
|
|
|
|
// Assert
|
|
Assert.IsTrue(validResult.IsSuccess);
|
|
Assert.AreEqual("user@example.com", validResult.Value);
|
|
|
|
// Act: 验证无效输入
|
|
var invalidResult = ValidateEmail("invalid");
|
|
|
|
// Assert
|
|
Assert.IsTrue(invalidResult.IsFailure);
|
|
Assert.AreEqual("Invalid email format", invalidResult.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 场景测试:数据库操作链
|
|
/// 演示如何使用 Result 处理可能失败的操作序列
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Scenario_DatabaseOperationChain()
|
|
{
|
|
// Act: 成功的操作链
|
|
var successResult = FindUserById(1)
|
|
.Bind(user => UpdateUserName(user, "NewName"))
|
|
.Bind(user => SaveUser(user))
|
|
.Map(user => $"User {user.Name} saved successfully");
|
|
|
|
// Assert
|
|
Assert.IsTrue(successResult.IsSuccess);
|
|
Assert.AreEqual("User NewName saved successfully", successResult.Value);
|
|
|
|
// Act: 失败的操作链(用户不存在)
|
|
var notFoundResult = FindUserById(999)
|
|
.Bind(user => UpdateUserName(user, "NewName"))
|
|
.Bind(user => SaveUser(user))
|
|
.Map(user => $"User {user.Name} saved successfully");
|
|
|
|
// Assert
|
|
Assert.IsTrue(notFoundResult.IsFailure);
|
|
Assert.IsTrue(notFoundResult.HasErrorCode(404L));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 场景测试:错误恢复
|
|
/// 演示使用 OrElse 提供备用逻辑
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void Scenario_ErrorRecovery()
|
|
{
|
|
// Act: 主操作失败,使用备用操作
|
|
var result = TryPrimaryOperation()
|
|
.OrElse(() => TryFallbackOperation())
|
|
.OrElse(() => Result.Success("Default value"));
|
|
|
|
// Assert
|
|
Assert.IsTrue(result.IsSuccess);
|
|
Assert.AreEqual("Fallback success", result.Value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 测试辅助方法
|
|
|
|
private Result<string> ValidateEmail(string email)
|
|
{
|
|
return email.AsResult()
|
|
.Ensure(e => !string.IsNullOrEmpty(e), "Email cannot be empty")
|
|
.Ensure(e => e.Contains("@"), "Invalid email format")
|
|
.Ensure(e => e.Length >= 5, "Email too short");
|
|
}
|
|
|
|
private class User
|
|
{
|
|
public int Id { get; set; }
|
|
public string Name { get; set; } = "";
|
|
}
|
|
|
|
private Result<User> FindUserById(int id)
|
|
{
|
|
return id == 1
|
|
? Result.Success(new User { Id = 1, Name = "John" })
|
|
: Result.Failure<User>(404L, "User not found");
|
|
}
|
|
|
|
private Result<User> UpdateUserName(User user, string newName)
|
|
{
|
|
user.Name = newName;
|
|
return Result.Success(user);
|
|
}
|
|
|
|
private Result<User> SaveUser(User user)
|
|
{
|
|
// 模拟保存成功
|
|
return Result.Success(user);
|
|
}
|
|
|
|
private Result<string> TryPrimaryOperation()
|
|
{
|
|
return Result.Failure<string>("Primary operation failed");
|
|
}
|
|
|
|
private Result<string> TryFallbackOperation()
|
|
{
|
|
return Result.Success("Fallback success");
|
|
}
|
|
|
|
#endregion
|
|
} |