gpt4 book ai didi

c# - 在 C# 中测试 Environment.Exit()

转载 作者:太空狗 更新时间:2023-10-29 22:21:37 27 4
gpt4 key购买 nike

在 C# 中是否有某种等价于 ExpectedSystemExit 的东西?在 java ?我的代码中有一个导出,我真的很想能够测试它。我在 C# 中发现的唯一东西是一个不太好的 workaround .

示例代码

public void CheckRights()
{
if(!service.UserHasRights())
{
Environment.Exit(1);
}
}

测试代码

[TestMethod]
public void TestCheckRightsWithoutRights()
{
MyService service = ...
service.UserHasRights().Returns(false);

???
}

我正在使用 VS 框架进行测试(+ NSubstitute 用于模拟),但切换到 nunit 或其他任何测试都不是问题。

最佳答案

您应该使用依赖注入(inject)为被测试的类提供一个提供环境导出的接口(interface)。

例如:

public interface IEnvironment
{
void Exit(int code);
}

我们还假设您有一个调用 UserHasRights() 的接口(interface):

public interface IRightsService
{
bool UserHasRights();
}

现在假设您要测试的类如下所示:

public sealed class RightsChecker
{
readonly IRightsService service;
readonly IEnvironment environment;

public RightsChecker(IRightsService service, IEnvironment environment)
{
this.service = service;
this.environment = environment;
}

public void CheckRights()
{
if (!service.UserHasRights())
{
environment.Exit(1);
}
}
}

现在您可以使用模拟框架来检查 IEnvironment .Exit() 是否在正确的条件下被调用。例如,使用 Moq 它可能看起来有点像这样:

[TestMethod]
public static void CheckRights_exits_program_when_user_has_no_rights()
{
var rightsService = new Mock<IRightsService>();
rightsService.Setup(foo => foo.UserHasRights()).Returns(false);

var enviromnent = new Mock<IEnvironment>();

var rightsChecker = new RightsChecker(rightsService.Object, enviromnent.Object);

rightsChecker.CheckRights();

enviromnent.Verify(foo => foo.Exit(1));
}

环境背景和跨领域问题

Environment.Exit() 之类的方法可以被认为是一个横切关注点,您可能希望避免为它传递一个接口(interface),因为您最终可能会得到一个额外构造函数参数的爆炸式增长。 (注意:横切关注点的典型示例是 DateTime.Now。)

为了解决这个问题,您可以引入“环境上下文”——一种允许您使用静态方法同时仍保留对它进行单元测试调用的能力的模式。当然,这些东西应该谨慎使用,并且只用于真正的横切关注点。

例如,您可以像这样为 Environment 引入环境上下文:

public abstract class EnvironmentControl
{
public static EnvironmentControl Current
{
get
{
return _current;
}

set
{
if (value == null)
throw new ArgumentNullException(nameof(value));

_current = value;
}
}

public abstract void Exit(int value);

public static void ResetToDefault()
{
_current = DefaultEnvironmentControl.Instance;
}

static EnvironmentControl _current = DefaultEnvironmentControl.Instance;
}

public class DefaultEnvironmentControl : EnvironmentControl
{
public override void Exit(int value)
{
Environment.Exit(value);
}

public static DefaultEnvironmentControl Instance => _instance.Value;

static readonly Lazy<DefaultEnvironmentControl> _instance = new Lazy<DefaultEnvironmentControl>(() => new DefaultEnvironmentControl());
}

普通代码只调用 EnvironmentControl.Current.Exit()。通过此更改,IEnvironment 参数从 RightsChecker 类中消失:

public sealed class RightsChecker
{
readonly IRightsService service;

public RightsChecker(IRightsService service)
{
this.service = service;
}

public void CheckRights()
{
if (!service.UserHasRights())
{
EnvironmentControl.Current.Exit(1);
}
}
}

但是我们仍然保留单元测试它被调用的能力:

public static void CheckRights_exits_program_when_user_has_no_rights()
{
var rightsService = new Mock<IRightsService>();
rightsService.Setup(foo => foo.UserHasRights()).Returns(false);

var enviromnent = new Mock<EnvironmentControl>();
EnvironmentControl.Current = enviromnent.Object;

try
{
var rightsChecker = new RightsChecker(rightsService.Object);
rightsChecker.CheckRights();
enviromnent.Verify(foo => foo.Exit(1));
}

finally
{
EnvironmentControl.ResetToDefault();
}
}

For more information about ambient contexts, see here.

关于c# - 在 C# 中测试 Environment.Exit(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37340870/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com