我的项目开始如下。我想创建一个单元测试来验证当appsetting.Environment.json
不存在或DataSource:JsonPath
文件不存在时发生的情况。
我正在使用xUnit,但是只是进入其中,
在这种情况下,它应该抛出FileNotFoundException
并退出。
internal class Program
{
private static int Main(string[] args)
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build();
try
{
Log.Information($"{DateTime.Now.ToLongTimeString()} Starting...");
var jsonFileName = Configuration["DataSource:JsonPath"];
if (!File.Exists(jsonFileName)) throw new FileNotFoundException(jsonFileName);
//code if file exist...
}
catch (Exception ex)
{
Log.Fatal(ex, "Terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
}
答案 0 :(得分:0)
在不更改任何代码的情况下,有两种方法可以做到这一点:
实际上使用Process
类运行该程序,并检查程序的退出代码(在Process.ExitCode
属性中公开)。在这种情况下,类别为internal
而Main
为private
的事实并不重要。
使用反射保留Main
方法并调用它,检查返回值。
如果这些都不是可口的,则可以将Main
更改为internal
并使用[InternalsVisibleTo]
属性来使您的单元测试无需反射就可以调用该方法。
对于所有这3种情况,如果退出代码为0,则测试通过,如果退出代码为2,则测试失败(假设没有其他可能的退出代码)。
答案 1 :(得分:0)
在最佳情况下,您会将Log
依赖项注入Main
或要测试的任何类中。然后,您将测试在开发的任何情况下都可以调用Log
方法。您还将注入配置和文件访问依赖关系,而不是紧密耦合,因此您不必实际在物理介质上进行真正的读/写访问来测试代码。就目前而言,您不能进行真实单元代码测试,因为您具有紧密耦合的外部依赖关系,因此您的代码在技术上正在进行集成测试。
我建议阅读Autofac DI container in console app。 (我与Autofac没有任何关联,我只是更喜欢它,而不是其他DI框架。如果您决定使用它们,则可以做很多研究。)如果要实现它,它可能看起来像这样:
internal class Program
{
private static int Main(string[] args)
{
var container = CreateContainer();
var worker = container.resolve<IWorker>();
worker.Execute();
}
}
internal class Worker : IWorker
{
private IConfiguration _configuration;
private IFileSystem _filesystem;
private ILog _log;
private IDateTimeFactory _datetimeFactory;
public Worker(
IConfiguration configuration,
IFileSystem filesystem,
ILog log,
IDateTimeFactory _datetimeFactory)
{
_configuration = configuration;
_filesystem = filesystem;
_log = log;
_datetimeFactory = datetimeFactory;
}
public void Execute()
{
try
{
_log.Information($"{_datetimeFactory.Now.ToLongTimeString()} Starting...");
var jsonFileName = _configuration["DataSource:JsonPath"];
if (!_filesystem.Exists(jsonFileName))
throw new FileNotFoundException(jsonFileName);
//code if file exist...
}
catch (Exception ex)
{
_log.Fatal(ex, "Terminated unexpectedly");
return 1;
}
finally
{
_log.CloseAndFlush();
}
}
}
以下是一个一般示例,我不能保证它可以100%工作。 现在,当我想测试工作人员时,我可以从字面上测试任何东西: (我假设您想使用nSubstitute和nUnit进行测试)
[TestFixture]
public WorkerTests
{
[Test]
public void Execute_ConfigurationFileNotFound_LogsException()
{
var config = Substitute.For<IConfiguration>();
var filesystem = Substitute.For<IFileSystem>();
var log = Substitute.For<ILog>();
var datetime = Substitute.For<IConfiIDateTimeFactory>();
var worker = new Worker(
config,
filesystem,
log,
datetime)
// setup the mock'd file system to always return false for Exists()
// That is what we're testing
filesystem.Exists(string.Empty).ReturnsForAnyArgs(false);
worker.Execute();
Assert.That(log.Received().Fatal(), Is.True);
}
}