[SettingName("TehApp")]
internal class TehApplicashun
{
public static readonly string Name = Assembly.GetAssembly(typeof(Program)).GetName().Name;
public static readonly string Version = "2.0.0";
private static readonly string GlobalFileName = "_Global.json";
private readonly ILogger _logger;
private readonly IPathResolver _pathResolver;
private readonly IFileSystem _fileSystem;
private readonly IVariableBuilder _variableBuilder;
private readonly AutofacContractResolver _autofacContractResolver;
private readonly TestRunner _testRunner;
public TehApplicashun(
ILogger logger,
IPathResolver pathResolver,
IFileSystem fileSystem,
IVariableBuilder variableBuilder,
AutofacContractResolver autofacContractResolver,
TestRunner testRunner)
{
_logger = logger;
_pathResolver = pathResolver;
_fileSystem = fileSystem;
_variableBuilder = variableBuilder;
_autofacContractResolver = autofacContractResolver;
_testRunner = testRunner;
}
public Workspace Workspace { get; set; }
public void Start(string[] args)
{
var globalFile = LoadGlobalFile();
var globals = VariableResolver.Empty
.MergeWith(globalFile.Globals)
.MergeWith(_variableBuilder.BuildVariables(Workspace));
var testFiles = LoadTestFiles().ToList();
LogEntry.New().Debug().Message($"Test files ({testFiles.Count}) loaded.").Log(_logger);
LogEntry.New().Info().Message($"*** {Name} v{Version} started. ***").Log(_logger);
_testRunner.RunTestFiles(testFiles, args, globals);
}
private GlobalFile LoadGlobalFile()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
var fileName = Path.Combine(targetsDirectoryName, GlobalFileName);
if (!File.Exists(fileName)) { return new GlobalFile(); }
try
{
var globalFileJson = File_fileSystem.ReadAllText(fileName);
var globalFile = JsonConvert.DeserializeObject<GlobalFile>(globalFileJson);
VariableValidator.ValidateNamesNotReserved(globalFile.Globals, _variableBuilder.Names);
LogEntry.New().Debug().Message($"{Path.GetFileName(fileName)} loaded.").Log(_logger);
return globalFile;
}
catch (Exception ex)
{
throw new InitializationException($"Could not load {Path.GetFileName(fileName)}.", ex);
}
}
[NotNull, ItemNotNull]
private IEnumerable<TestFile> LoadTestFiles()
{
LogEntry.New().Debug().Message("Initializing tests...").Log(_logger);
return
GetTestFileNames()
.Select(LoadTest)
.Where(Conditional.IsNotNull);
}
[NotNull, ItemNotNull]
private IEnumerable<string> GetTestFileNames()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
return
from fullName in _fileSystem.GetFiles(targetsDirectoryName, "*.json")
where !Path.GetFileName(fullName).StartsWith("_", StringComparison.OrdinalIgnoreCase)
select fullName;
}
[CanBeNull]
private TestFile LoadTest(string fileName)
{
var logEntry = LogEntry.New().Info();
try
{
var json = _fileSystem.ReadAllText(fileName);
var testFile = JsonConvert.DeserializeObject<TestFile>(json, new JsonSerializerSettings
{
ContractResolver = _autofacContractResolver,
DefaultValueHandling = DefaultValueHandling.Populate,
TypeNameHandling = TypeNameHandling.Auto,
});
testFile.FullName = fileName;
VariableValidator.ValidateNamesNotReserved(testFile.Locals, _variableBuilder.Names);
logEntry.Message($"Test initialized: {fileName}");
return testFile;
}
catch (Exception ex)
{
logEntry.Error().Message($"Could not initialize test: {fileName}").Exception(ex);
return null;
}
finally
{
logEntry.Log(_logger);
}
}
}
[SettingName("TehApp")]
internal class TehApplicashun
{
public static readonly string Name = Assembly.GetAssembly(typeof(Program)).GetName().Name;
public static readonly string Version = "2.0.0";
private static readonly string GlobalFileName = "_Global.json";
private readonly ILogger _logger;
private readonly IPathResolver _pathResolver;
private readonly IFileSystem _fileSystem;
private readonly IVariableBuilder _variableBuilder;
private readonly AutofacContractResolver _autofacContractResolver;
private readonly TestRunner _testRunner;
public TehApplicashun(
ILogger logger,
IPathResolver pathResolver,
IFileSystem fileSystem,
IVariableBuilder variableBuilder,
AutofacContractResolver autofacContractResolver,
TestRunner testRunner)
{
_logger = logger;
_pathResolver = pathResolver;
_fileSystem = fileSystem;
_variableBuilder = variableBuilder;
_autofacContractResolver = autofacContractResolver;
_testRunner = testRunner;
}
public Workspace Workspace { get; set; }
public void Start(string[] args)
{
var globalFile = LoadGlobalFile();
var globals = VariableResolver.Empty
.MergeWith(globalFile.Globals)
.MergeWith(_variableBuilder.BuildVariables(Workspace));
var testFiles = LoadTestFiles().ToList();
LogEntry.New().Debug().Message($"Test files ({testFiles.Count}) loaded.").Log(_logger);
LogEntry.New().Info().Message($"*** {Name} v{Version} started. ***").Log(_logger);
_testRunner.RunTestFiles(testFiles, args, globals);
}
private GlobalFile LoadGlobalFile()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
var fileName = Path.Combine(targetsDirectoryName, GlobalFileName);
if (!File.Exists(fileName)) { return new GlobalFile(); }
try
{
var globalFileJson = File.ReadAllText(fileName);
var globalFile = JsonConvert.DeserializeObject<GlobalFile>(globalFileJson);
VariableValidator.ValidateNamesNotReserved(globalFile.Globals, _variableBuilder.Names);
LogEntry.New().Debug().Message($"{Path.GetFileName(fileName)} loaded.").Log(_logger);
return globalFile;
}
catch (Exception ex)
{
throw new InitializationException($"Could not load {Path.GetFileName(fileName)}.", ex);
}
}
[NotNull, ItemNotNull]
private IEnumerable<TestFile> LoadTestFiles()
{
LogEntry.New().Debug().Message("Initializing tests...").Log(_logger);
return
GetTestFileNames()
.Select(LoadTest)
.Where(Conditional.IsNotNull);
}
[NotNull, ItemNotNull]
private IEnumerable<string> GetTestFileNames()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
return
from fullName in _fileSystem.GetFiles(targetsDirectoryName, "*.json")
where !Path.GetFileName(fullName).StartsWith("_", StringComparison.OrdinalIgnoreCase)
select fullName;
}
[CanBeNull]
private TestFile LoadTest(string fileName)
{
var logEntry = LogEntry.New().Info();
try
{
var json = _fileSystem.ReadAllText(fileName);
var testFile = JsonConvert.DeserializeObject<TestFile>(json, new JsonSerializerSettings
{
ContractResolver = _autofacContractResolver,
DefaultValueHandling = DefaultValueHandling.Populate,
TypeNameHandling = TypeNameHandling.Auto,
});
testFile.FullName = fileName;
VariableValidator.ValidateNamesNotReserved(testFile.Locals, _variableBuilder.Names);
logEntry.Message($"Test initialized: {fileName}");
return testFile;
}
catch (Exception ex)
{
logEntry.Error().Message($"Could not initialize test: {fileName}").Exception(ex);
return null;
}
finally
{
logEntry.Log(_logger);
}
}
}
[SettingName("TehApp")]
internal class TehApplicashun
{
public static readonly string Name = Assembly.GetAssembly(typeof(Program)).GetName().Name;
public static readonly string Version = "2.0.0";
private static readonly string GlobalFileName = "_Global.json";
private readonly ILogger _logger;
private readonly IPathResolver _pathResolver;
private readonly IFileSystem _fileSystem;
private readonly IVariableBuilder _variableBuilder;
private readonly AutofacContractResolver _autofacContractResolver;
private readonly TestRunner _testRunner;
public TehApplicashun(
ILogger logger,
IPathResolver pathResolver,
IFileSystem fileSystem,
IVariableBuilder variableBuilder,
AutofacContractResolver autofacContractResolver,
TestRunner testRunner)
{
_logger = logger;
_pathResolver = pathResolver;
_fileSystem = fileSystem;
_variableBuilder = variableBuilder;
_autofacContractResolver = autofacContractResolver;
_testRunner = testRunner;
}
public Workspace Workspace { get; set; }
public void Start(string[] args)
{
var globalFile = LoadGlobalFile();
var globals = VariableResolver.Empty
.MergeWith(globalFile.Globals)
.MergeWith(_variableBuilder.BuildVariables(Workspace));
var testFiles = LoadTestFiles().ToList();
LogEntry.New().Debug().Message($"Test files ({testFiles.Count}) loaded.").Log(_logger);
LogEntry.New().Info().Message($"*** {Name} v{Version} started. ***").Log(_logger);
_testRunner.RunTestFiles(testFiles, args, globals);
}
private GlobalFile LoadGlobalFile()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
var fileName = Path.Combine(targetsDirectoryName, GlobalFileName);
if (!File.Exists(fileName)) { return new GlobalFile(); }
try
{
var globalFileJson = _fileSystem.ReadAllText(fileName);
var globalFile = JsonConvert.DeserializeObject<GlobalFile>(globalFileJson);
VariableValidator.ValidateNamesNotReserved(globalFile.Globals, _variableBuilder.Names);
LogEntry.New().Debug().Message($"{Path.GetFileName(fileName)} loaded.").Log(_logger);
return globalFile;
}
catch (Exception ex)
{
throw new InitializationException($"Could not load {Path.GetFileName(fileName)}.", ex);
}
}
[NotNull, ItemNotNull]
private IEnumerable<TestFile> LoadTestFiles()
{
LogEntry.New().Debug().Message("Initializing tests...").Log(_logger);
return
GetTestFileNames()
.Select(LoadTest)
.Where(Conditional.IsNotNull);
}
[NotNull, ItemNotNull]
private IEnumerable<string> GetTestFileNames()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
return
from fullName in _fileSystem.GetFiles(targetsDirectoryName, "*.json")
where !Path.GetFileName(fullName).StartsWith("_", StringComparison.OrdinalIgnoreCase)
select fullName;
}
[CanBeNull]
private TestFile LoadTest(string fileName)
{
var logEntry = LogEntry.New().Info();
try
{
var json = _fileSystem.ReadAllText(fileName);
var testFile = JsonConvert.DeserializeObject<TestFile>(json, new JsonSerializerSettings
{
ContractResolver = _autofacContractResolver,
DefaultValueHandling = DefaultValueHandling.Populate,
TypeNameHandling = TypeNameHandling.Auto,
});
testFile.FullName = fileName;
VariableValidator.ValidateNamesNotReserved(testFile.Locals, _variableBuilder.Names);
logEntry.Message($"Test initialized: {fileName}");
return testFile;
}
catch (Exception ex)
{
logEntry.Error().Message($"Could not initialize test: {fileName}").Exception(ex);
return null;
}
finally
{
logEntry.Log(_logger);
}
}
}
It wasn't easy but I managed to move all code that needs to be tested into a new TehApplicashun
class - I know, lolcat speak :-) that now receives a bunch of serivces and is created by Autofac too. Everything is abstracted and everything can be replaced for testing. Now I can test the application's behavior for example to verfiy it exits if one of the requried files is missing or doesn't crash if an optional one is invalid.
[SettingName("TehApp")]
internal class TehApplicashun
{
public static readonly string Name = Assembly.GetAssembly(typeof(Program)).GetName().Name;
public static readonly string Version = "2.0.0";
private static readonly string GlobalFileName = "_Global.json";
private readonly ILogger _logger;
private readonly IPathResolver _pathResolver;
private readonly IFileSystem _fileSystem;
private readonly IVariableBuilder _variableBuilder;
private readonly AutofacContractResolver _autofacContractResolver;
private readonly TestRunner _testRunner;
public TehApplicashun(
ILogger logger,
IPathResolver pathResolver,
IFileSystem fileSystem,
IVariableBuilder variableBuilder,
AutofacContractResolver autofacContractResolver,
TestRunner testRunner)
{
_logger = logger;
_pathResolver = pathResolver;
_fileSystem = fileSystem;
_variableBuilder = variableBuilder;
_autofacContractResolver = autofacContractResolver;
_testRunner = testRunner;
}
public Workspace Workspace { get; set; }
public void Start(string[] args)
{
var globalFile = LoadGlobalFile();
var globals = VariableResolver.Empty
.MergeWith(globalFile.Globals)
.MergeWith(_variableBuilder.BuildVariables(Workspace));
var testFiles = LoadTestFiles().ToList();
LogEntry.New().Debug().Message($"Test files ({testFiles.Count}) loaded.").Log(_logger);
LogEntry.New().Info().Message($"*** {Name} v{Version} started. ***").Log(_logger);
_testRunner.RunTestFiles(testFiles, args, globals);
}
private GlobalFile LoadGlobalFile()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
var fileName = Path.Combine(targetsDirectoryName, GlobalFileName);
if (!File.Exists(fileName)) { return new GlobalFile(); }
try
{
var globalFileJson = File.ReadAllText(fileName);
var globalFile = JsonConvert.DeserializeObject<GlobalFile>(globalFileJson);
VariableValidator.ValidateNamesNotReserved(globalFile.Globals, _variableBuilder.Names);
LogEntry.New().Debug().Message($"{Path.GetFileName(fileName)} loaded.").Log(_logger);
return globalFile;
}
catch (Exception ex)
{
throw new InitializationException($"Could not load {Path.GetFileName(fileName)}.", ex);
}
}
[NotNull, ItemNotNull]
private IEnumerable<TestFile> LoadTestFiles()
{
LogEntry.New().Debug().Message("Initializing tests...").Log(_logger);
return
GetTestFileNames()
.Select(LoadTest)
.Where(Conditional.IsNotNull);
}
[NotNull, ItemNotNull]
private IEnumerable<string> GetTestFileNames()
{
var targetsDirectoryName = _pathResolver.ResolveDirectoryPath(Workspace.Targets);
return
from fullName in _fileSystem.GetFiles(targetsDirectoryName, "*.json")
where !Path.GetFileName(fullName).StartsWith("_", StringComparison.OrdinalIgnoreCase)
select fullName;
}
[CanBeNull]
private TestFile LoadTest(string fileName)
{
var logEntry = LogEntry.New().Info();
try
{
var json = _fileSystem.ReadAllText(fileName);
var testFile = JsonConvert.DeserializeObject<TestFile>(json, new JsonSerializerSettings
{
ContractResolver = _autofacContractResolver,
DefaultValueHandling = DefaultValueHandling.Populate,
TypeNameHandling = TypeNameHandling.Auto,
});
testFile.FullName = fileName;
VariableValidator.ValidateNamesNotReserved(testFile.Locals, _variableBuilder.Names);
logEntry.Message($"Test initialized: {fileName}");
return testFile;
}
catch (Exception ex)
{
logEntry.Error().Message($"Could not initialize test: {fileName}").Exception(ex);
return null;
}
finally
{
logEntry.Log(_logger);
}
}
}
Additionaly I had to create a new small service to be able to fake the file-system and simulate missing or invalid file.
[PublicAPI]
internal interface IFileSystem
{
string ReadAllText(string fileName);
string[] GetFiles(string path, string searchPattern);
}
internal class FileSystem : IFileSystem
{
public string ReadAllText(string fileName)
{
return File.ReadAllText(fileName);
}
public string[] GetFiles(string path, string searchPattern)
{
return Directory.GetFiles(path, searchPattern);
}
}
The new Main
is now nice and small. Jut resolve TehApplicashun
and Start
.
private static int Main(string[] args)
{
var mainLogEntry =
LogEntry
.New()
.MessageBuilder(sb => sb.Append($"*** {TehApplicashun.Name} v{TehApplicashun.Version}"))
.Stopwatch(sw => sw.Start());
try
{
var container = InitializeContainer().GetAwaiter().GetResult();
using (var scope = container.BeginLifetimeScope())
{
var tehApp = scope.Resolve<TehApplicashun>();
tehApp.Start(args);
}
mainLogEntry.Info().MessageBuilder(sb => sb.Append("completed."));
return 0;
}
catch (Exception ex)
{
mainLogEntry.Fatal().MessageBuilder(sb => sb.Append("crashed.")).Exception(ex);
return 1;
}
finally
{
mainLogEntry.MessageBuilder(sb => sb.Append(" ***")).Log(Logger);
}
}
I still need to clean-up the container configuration but this shouldn't be easy done with autofac-modules also exchangable for testing.