我有一些功能,这取决于命令行参数,不同的参数应该导致不同的结果。
我不能直接"模拟"这个参数,因为存在某种链依赖性 - 我需要对一些xaml控件进行单元测试,这取决于视图模型,它依赖于某些额外的类,它使用Environment.GetCommandLineArgs
获取命令行参数,而我不能直接影响最后一个类来手动设置参数,而不是使用GetCommandLineArgs
。
所以,我想知道,有没有办法让Environment.GetCommandLineArgs
返回值,我希望它返回,以进行某些单元测试。
答案 0 :(得分:3)
你需要抽象Bar4
或者最终在你可以模拟的东西之后调用它
Environment.GetCommandLineArgs
最终可以在具体的类中实现,如
public interface ICommandLineInterface {
string[] GetCommandLineArgs();
}
可以使用public class CommandInterface : ICommandLineInterface {
public string[] GetCommandLineArgs() {
return Environment.GetCommandLineArgs();
}
}
和Moq
FluentAssertions
答案 1 :(得分:1)
由于您正在处理环境变量,为什么我们不将外部依赖项包装到一个EnvironmentHelper类中,然后注入依赖项?
这是我的建议:
public class EnvironmentHelper
{
Func<string[]> getEnvironmentCommandLineArgs;
// other dependency injections can be placed here
public EnvironmentHelper(Func<string[]> getEnvironmentCommandLineArgs)
{
this.getEnvironmentCommandLineArgs = getEnvironmentCommandLineArgs;
}
public string[] GetEnvironmentCommandLineArgs()
{
return getEnvironmentCommandLineArgs();
}
}
这是Mock方法:
public static string[] GetFakeEnvironmentCommandLineArgs()
{
return new string[] { "arg1", "arg2" };
}
在您的源代码中:
EnvironmentHelper envHelper = new EnvironmentHelper(Environment.GetCommandLineArgs);
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs();
在您的单元测试代码中:
EnvironmentHelper envHelper = new EnvironmentHelper(GetFakeEnvironmentCommandLineArgs);
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs();
答案 2 :(得分:0)
如果你想要一些可单元测试的东西,它应该依赖于一个至少和它的实现一样严格的抽象。
通常,您将通过类的构造函数或属性方法获取依赖项。通常,构造函数是首选,因为现在您的类的使用者在编译时知道需要哪些依赖项。
public void int Main(string[] args)
{
// Validate the args are valid (not shown).
var config = new AppConfig();
config.Value1 = args[0];
config.Value2 = int.Parse(args[1]);
// etc....
}
public class MyService()
{
private AppConfig _config;
public MyService(AppConfig config)
{
this._config = config;
}
}
我通常不会在接口后面放置一个配置对象,因为它只有数据 - 可以序列化。只要它没有方法,那么我就不需要用具有override
- d行为的子类替换它。我也可以在我的测试中直接new
。
另外,当我想依赖于命令行参数本身对服务的抽象时,我从未遇到过这种情况 - 为什么它需要知道它在命令行后面?我得到的最接近的是使用PowerArgs来轻松解析,但我会在Main
中使用该权限。我通常做的就是在命令行参数上读取Web服务器的端口号(我让应用程序的用户选择这样我可以在同一台机器上运行我的Web服务器的多个副本 - 可能不同版本左右我可以在调试时运行自动化测试,而不是冲突端口),直接在我的Main
类中解析它们。然后在我的Web服务器中,我依赖于解析的命令行参数,在本例中为int
。这样,配置来自命令行的事实是无关紧要的 - 如果我愿意,我可以稍后将其移动到App.config
文件(这也基本上绑定到流程的生命周期) - 然后我就可以了将常用配置提取到configSource
个文件。
不是依赖于命令行的抽象(如果保持纯粹,每个服务消耗都必须重新解析),我通常会将命令行和App.config
依赖项抽象为强-typed对象 - 可能是app级配置类和测试级配置类,并根据需要引入多个配置对象 - (应用程序不一定会关心这一点,而E2E测试基础设施需要在单独的部分中App.config
:我从哪里获取客户端静态文件,在哪里获取测试或开发人员环境中的构建脚本以自动生成/自动更新index.html文件等。)。 p>
答案 3 :(得分:0)
使用an array可以更轻松地完成此任务。 它允许不仅模拟接口,所以。看看:
[TestMethod, Isolated]
public void TestFakeArgs()
{
//Arrange
Isolate.WhenCalled(() => Environment.GetCommandLineArgs()).WillReturn(new[] { "Your", "Fake", "Args" });
//Act
string[] args = Environment.GetCommandLineArgs();
//Assert
Assert.AreEqual("Your", args[0]);
Assert.AreEqual("Fake", args[0]);
Assert.AreEqual("Args", args[0]);
}
模拟Environment.GetCommandLineArgs()
只占用一行:
Isolate.WhenCalled(() => Environment.GetCommandLineArgs()).WillReturn(new[] { "Your", "Fake", "Args" });
您无需创建新接口并更改生产代码。
希望它有所帮助!