How to write test case for Run time Assembly Location - c#

Here is my class which create new application instance:
public interface IApplicationInstanceProvider
{
bool CreateNewProcess();
}
public class ApplicationInstanceProvider : IApplicationInstanceProvider
{
public bool CreateNewProcess()
{
Process p = new Process();
p.StartInfo.FileName = System.Reflection.Assembly.GetEntryAssembly().Location;
return p.Start();
}
}
Here is my test case:
[TestMethod]
public void TestMethodForAppInstance()
{
IApplicationInstanceProvider provider = new ApplicationInstanceProvider();
bool isCreated = provider.CreateNewProcess();
Assert.AreEqual(isCreated,true);
}
Here is problem: System.Reflection.Assembly.GetEntryAssembly() is null while test case execution. But it works fine while application running.
Please help!

You can't test your class as-is because you're executing an unknown new process in the test environment. It's not viable because:
Assembly.GetEntryAssembly() will return null.
Whatever it returns you'll execute that process and it may be, let's say, devenv.exe, chrome.exe or whatever.
CreateNewProcess() method does many things: it determines program to execute path and it run it. Moreover its return value tells caller if a new process has been started or an existing one has been reused. Too many things for a single method make it hard to test. Fortunately there are at least two approaches to make your code testable: create a specialized ApplicationInstanceProvider class for testing or make a separate class for it.
Let's see FIRST METHOD:
public class ApplicationInstanceProvider : IApplicationInstanceProvider {
public bool CreateNewProcess() {
Process process = new Process();
process.StartInfo.FileName = ResolveApplicationPath();
return process.Start();
}
protected virtual string ResolveApplicationPath() {
return System.Reflection.Assembly.GetEntryAssembly().Location;
}
}
You'll create a derived class for testing:
sealed class TestApplicationInstanceProvider : ApplicationInstanceProvider {
protected override string ResolveApplicationPath() {
// path to your assembly or a well-known executable executable
// Like %WINDIR%\notepad.exe
return "...";
}
}
It'll be then used like this in your test method:
[TestMethod]
public void TestMethodForAppInstance() {
var provider = new TestApplicationInstanceProvider();
bool isCreated = provider.CreateNewProcess();
Assert.AreEqual(isCreated, true);
}
Note that you cannot test Assembly.GetEntryAssembly() but you can test everything els. Note that now you're testing if you create a new process instance but you do not check you started right one; this will increase code coverage but you're actually testing almost nothing because Process.Start() will always return true for executables (running process may be reused for documents). That's why you have to split CreateNewProcess() responsabilities (not only for clarity but for testing). Do not forget to close process instance in your cleanup method after testing!
Let's see SECOND METHOD: second method is little bit more complicated but it's more versatile:
public interface IAssemblyResolver {
string GetEntryAssemblyPath();
}
public sealed class DefaultAssemblyResolver : IAssemblyResolver {
public string GetEntryAssemblyPath() {
return System.Reflection.Assembly.GetEntryAssembly().Location;
}
}
public class ApplicationInstanceProvider : IApplicationInstanceProvider {
public ApplicationInstanceProvider(IAssemblyResolver resolver) {
_resolver = resolver;
}
public bool CreateNewProcess() {
Process process = new Process();
process.StartInfo.FileName = _resolver.GetEntryAssemblyPath();
return process.Start();
}
private readonly IAssemblyResolver _resolver;
}
Now you have to create a mock for testing:
sealed class TestAssemblyResolver : IAssemblyResolver {
public string GetEntryAssemblyPath() {
// Return path of a well-known test application,
// for example an "empty" console application. You can also
// reuse it to, for example, return different error codes
return Assembly.Load(...);
}
}
Test method:
[TestMethod]
public void TestMethodForAppInstance() {
var resolver = new TestAssemblyResolver();
var provider = new ApplicationInstanceProvider(resolver);
bool isCreated = provider.CreateNewProcess();
Assert.AreEqual(isCreated, true);
}
What your fake application may look like?
static class Program {
static int Main(string[] args) {
if (args.Length == 0)
return 0;
return Int32.Parse(args[0]);
}
}

Related

Executing Powershell Cmdlets Code in C#

How would I use the code used to create powershell cmdlets in another c# method instead of a powershell script.
I have the following code:
public class Program
{
static void Main(string[] args)
{
var getCommand = new GetCommand { Text = "Hello World"};
//help needed here
}
}
[Cmdlet("Test", "Get")]
public class GetCommand : Cmdlet
{
[Parameter(Mandatory = true)]
public string Text { get; set; }
protected override void ProcessRecord()
{
WriteObject(Text);
}
}
Don't instantiate the GetCommand class - PowerShell will do that for you!
First, you'll need to spin up an instance of the PowerShell class to execute your command:
PowerShell ps = PowerShell.Create();
Then add a CommandInfo reference with the AddCommand method:
ps.AddCommand(new CmdletInfo("Test-Get", typeof(GetCommand)));
And then add your parameter argument:
ps.AddParameter("Text", "Hello World");
Now you can execute it (and collect the output) with the Invoke() method:
var output = ps.Invoke();
foreach(var obj in ouput)
{
Console.WriteLine("Output was: {0}", obj);
}
Extract the logic in a seperate class and call it directly. Use the cmdlet to be, well, just a shell around this new class.
This Seperation of Concerns (SoC) also enables easier unit tests and leads to an overall cleaner architecture.
Extracted Class Greeter.cs
public class Greeter {
public Greeter(string name) {
_Name = name;
}
private string _Name;
public string SayHello() {
return $"Hello {_Name}";
}
public string SayGoodBye() {
return $"So long {_Name}, and thanks for all the fish!";
}
}
CommandLet GetGreetingCommand.cs
[Cmdlet("Greeting", "Get")]
public class GetGreetingCommand : Cmdlet {
[Parameter(Mandatory = true)]
public string Name { get; set; }
protected override void ProcessRecord() {
var greeter = new Greeter(Name);
var greeting = greeter.SayHello();
WriteObject(greeting);
}
}
CommandLet GetGoodByeCommand .cs
[Cmdlet("GoodBye", "Get")]
public class GetGoodByeCommand : Cmdlet {
[Parameter(Mandatory = true)]
public string Name { get; set; }
protected override void ProcessRecord() {
var greeter = new Greeter(Name);
var goodBye = greeter.SayGoodBye();
WriteObject(goodBye);
}
}
Console Main.cs (or any other client-code of Greeter-class)
public static void main(string[] args) {
var greeter = new Greeter(args.FirstOrDefault());
Console.WriteLine(greeter.SayHello());
Console.WriteLine(greeter.SayGoodBye());
}
TestCase
public static void SayingHelloUsesName() {
var sut = new Greeter("Arthur");
var expected = "Hello Arthur";
var actual = sut.SayHello();
Assert.AreEqual(expected, actual);
}
The two concerns here are
- the actual BusinessLogic (Greeter.cs)
- interoperability with PowerShell, providing mechanisms to parameterize the cmdlet, etc. (Get*Command.cs). As you see, the cmdlets really only pass through the calls, while enabling use via PowerShell.
#Mathias R. Jessen ยด answer could be usefull, if you need to call third party cmdlets, but in most cases, there should be an appropriate (non-powershell) API for what you are trying to do.

unit test on a static function that read a file

I have the followed function and trying to add Unit Test on a old project. I'm a beginner in Unit Test so forgive me if the question is stupid ...
public static string GetDefaultName(bool isResponsive)
{
//Read web.config file
Configuration configuration = WebConfigurationManager.OpenWebConfiguration(System.Web.HttpContext.Current.Request.ApplicationPath);
if (!isResponsive)
{
if (configuration.AppSettings.Settings.AllKeys.Contains("defaultTheme"))
{
return configuration.AppSettings.Settings["defaultTheme"].Value;
}
else
return "default";
}
else
{
// ...
}
}
And I'm trying to write an Unit Test in this way :
[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive()
{
var theme = new Theme {isResponsive = true};
var defaultName = Themes.GetDefaultName(theme.isResponsive);
Assert.AreEqual(defaultName, "defaultThemeResponsive");
}
I wonder what is the best way to test this static function, and how to mock the part who read the web.config file ?
I try to stay away from static utilities that have dependencies as they are difficult to unit test. But in this case it is possible. You will have to do some refactoring.
First you need to abstract all calls to access configuration.
public interface IThemeSettings {
bool Contains(string key);
string this[string key] { get; }
}
You can then update the static Themes utility class to use this abstraction as a dependency
public static class Themes {
private static IThemeSettings themes;
public static void Configure(Func<IThemeSettings> factory) {
if (factory == null) throw new InvalidOperationException("Must provide a valid factory method");
themes = factory();
}
public static string GetDefaultName(bool isResponsive) {
if (themes == null) throw new InvalidOperationException("Themes has not been configured.");
string result = string.Empty;
if (!isResponsive) {
if (themes.Contains("defaultTheme")) {
result = themes["defaultTheme"];
} else
result = "default";
} else {
// ...
}
return result;
}
//...
}
That wat you can now configure the utility to use mocks when testing
[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive() {
//Arrange
var key = "defaultTheme";
var expected = "defaultThemeResponsive";
var mockSettings = new Mock<IThemeSettings>();
mockSettings.Setup(m => m.Contains(key)).Returns(true);
mockSettings.Setup(m => m[key]).Returns(expected);
//In production you would also do something like this with
//the actual production implementation, not a mock
Themes.Configure(() => mockSettings.Object);
var theme = new Theme { isResponsive = true };
//Act
var defaultName = Themes.GetDefaultName(theme.isResponsive);
//Assert
Assert.AreEqual(expected, defaultName);
}
In this case I used Moq as the mocking framework.
Some advice. Try not to have your classes tightly coupled to HttpContext. Your classes should depend on abstractions and not on concretions.
The way your method is designed at the moment does not allow you to mock the part that reads the config file. If you want to be able to do that you need to make it a parameter to your method. One way to make that easier is to define an interface like
public interface ISetting
{
string GetConfigItem(string itemName);
}
Then wrap the Configuration object in a settings manager class that implements this.
public class MySettings:ISetting
{
public string GetConfigItem(string ItemName)
{
// return value of the setting. In your case code that gets value of "defaultTheme"
}
}
Your method will now have a dependency on ISetting.
For testing purposes you can create a mock that implements the interface and will return what ever value you want independent of the current state and content of the web.config
public class SettingsTestHelper:ISetting
{
private _valueToReturn;
public SettingsTestHelper(string valueToReturn)
{
_valueToReturn=valueToReturn;
}
public string GetConfigItem(string itemName)
{
return valueToReturn;
}
}
With this you can now create a unit test(doesn't compile, but you'll get the idea)
[TestMethod]
public void CanGetSetting()
{
var helper = new SettingsTestHelper("default");
var result = ClasThatImplementsYourStaticMethod.GetDefaultName(helper, true);
Assert.AreEqual(expected, actual);
}

How can I use a separate AppDomain for each xUnit.net test method?

xUnit uses the same AppDomain for the whole test assembly, this is problematic as I'm testing a UI library and need to create a new Application instance for each individual test.
It works when I run a single test, but when I Run All the first test passed, but all subsequent tests fail with Cannot create more than one System.Windows.Application instance in the same AppDomain at the line where I create a new Application object.
Perhaps you could try by making your test class like this:
public class DomainIsolatedTests : IDisposable
{
private static int index = 0;
private readonly AppDomain testDomain;
public DomainIsolatedTests()
{
var name= string.Concat("TestDomain #", ++index);
testDomain = AppDomain.CreateDomain(name, AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
// Trace.WriteLine(string.Format("[{0}] Created.", testDomain.FriendlyName));
}
public void Dispose()
{
if (testDomain != null)
{
// Trace.WriteLine(string.Format("[{0}] Unloading.", testDomain.FriendlyName));
AppDomain.Unload(testDomain);
}
}
[Fact]
public void Test1()
{
testDomain.DoCallBack(() => {
var app = new System.Windows.Application();
...
// assert
});
}
[Fact]
public void Test2()
{
testDomain.DoCallBack(() => {
var app = new System.Windows.Application();
...
// assert
});
}
[Fact]
public void Test3()
{
testDomain.DoCallBack(() => {
var app = new System.Windows.Application();
...
// assert
});
}
...
}
Maybe, foreach Test you can dynamically load your assembly in a new Domain.
public static void DynamicExecution(String assemblyFileName, String uniqueDomName)
{
Boolean retVal = false;
AppDomain newDomain = AppDomain.CreateDomain(uniqueDomName);
YourClass yourClass = (YourClass)newDomain.CreateInstanceFromAndUnwrap(assemblyFileName, "YourClass");
//do what you need with yourClass Object
AppDomain.Unload(newDomain);
newDomain = null;
}
AppDomain appDomain = AppDomain.CreateDomain("WorkerDomain " + Thread.CurrentThread.Name);
var domain = (AppDomainWorker)appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(AppDomainWorker).FullName);
domain.Executor();
internal class AppDomainWorker
{
internal object Executor ()
{
// your unit test can run here
}
}
Two more important things:
1) You might need to mark class as MarshalByRefObject and override InitializeLifetimeService method to have a object longer life or existence. MarshalByRefObject will be needed in case you have to communicate between appdomains. For details on this read up on Microsoft remoting concept.
2) Sometime we might need to assembly resolution in AppDomains, if it does not take the Assemblies loaded in the parent domain but it is in very rare cases.

Fetch Program ApplicationExitCode for Unit Test

I would like to check the ApplicationExitCode for my C# Console Program under test. Below is my NUnit test method. I am uncertain what to replace the question marks with.
My testing class method:
[Test]
public void ExitApplicationWithZeroOnNoErrors()
{
string[] arguments = { "--version=43" };
var program = new Program(arguments);
Assert.AreEqual(Utility.Status.Success, ?????);
}
My main application Program.cs.
public class Program
{
public int? Version { get; private set; }
[STAThread]
public static int Main(string[] arguments)
{
var program = new Program(arguments);
return (int)Utility.Status.Success;
}
public Program(IEnumerable<string> arguments)
{
var parameters = new OptionSet()
{
{"v|version=", "Client version number.", (int v) => Version = v},
};
parameters.Parse(arguments);
}
}
As an aside I am using NDesk.Options class for my parameter gathering. I attempting to write Unit Tests and utilize TDD for this project.
In order to check the exit code as would be returned to the OS, you should check the value returned from Main. So you will have to run Main:
var returnValue = Program.Main(arguments);
Assert.AreEqual(Utility.Status.Success, returnValue);

How write stub method with NUnit in C#

I have 2 classes:
FirstDeep.cs
SecondDeep.cs
I did simple code for example:
class FirstDeep
{
public FirstDeep() { }
public string AddA(string str)
{
SecondDeep sd = new SecondDeep();
bool flag = sd.SomethingToDo(str);
if (flag == true)
str = string.Concat(str, "AAA");
else
str = string.Concat(str, "BBB");
return str;
}
}
and
class SecondDeep
{
public bool SomethingToDo(string str)
{
bool flag = false;
if (str.Length < 10)
{
//todo something in DB, and after that flag should be TRUE
}
return flag;
}
}
Then I want to write unit test for method "AddA":
class Tests
{
[Test]
public void AddATest()
{
string expected = "ABCAAA";
FirstDeep fd = new FirstDeep();
string res = fd.AddA("ABC");
Assert.AreEqual(expected, res);
}
}
And after that I have trouble, I don't know how correct write stub for method SomethingToDo in my Test class. I always have false. I should just return TRUE. But how?
A good way to allow you to write stubs is to use dependency injection. FirstDeep depends on SecondDeep and in your test you want to replace SecondDeep with a stub.
First change your existing code by extracting an interface for SecondDeep and then inject that into FirstDeep in the constructor:
interface ISecondDeep {
Boolean SomethingToDo(String str);
}
class SecondDeep : ISecondDeep { ... }
class FirstDeep {
readonly ISecondDeep secondDeep;
public FirstDeep(ISecondDeep secondDeep) {
this.secondDeep = secondDeep;
}
public String AddA(String str) {
var flag = this.secondDeep.SomethingToDo(str);
...
}
}
Note that FirstDeep no longer creates a SecondDeep instance. Instead an instance is injected in the constructor.
In your test you can create a stub for ISecondDeep where SomethingToDo always returns true:
class SecondDeepStub : ISecondDeep {
public Boolean SomethingToDo(String str) {
return true;
}
}
In the test you use the stub:
var firstDeep = new FirstDeep(new SecondDeepStub());
In production code you use the "real" SecondDeep:
var firstDeep = new FirstDeep(new SecondDeep());
Using a dependency injection container and a stubbing framework can make a lot of this easier to do.
If you don't want to rewrite your code you can use a framework for intercepting calls like Microsoft Moles. In the next version of Visual Studio a similar technology will be available in the Fakes Framework.
To make your code testable, do not instantiate dependencies inside your class. Use dependency injection (via constructor, property or parameter). Also use abstract classes or interfaces to allow mocking of dependencies:
class FirstDeep
{
private ISecondDeep oa;
public FirstDeep(ISecondDeep oa)
{
this.oa = oa;
}
public string AddA(string str)
{
return String.Concat(str, oa.SomethingToDo(str) ? "AAA" : "BBB");
}
}
Depending on abstractions allows you to test your class in isolation.
interface ISecondDeep
{
bool SomethingToDo(string str);
}
class SecondDeep : ISecondDeep
{
public bool SomethingToDo(string str)
{
bool flag = false;
if (str.Length < 10)
{
// without abstraction your test will require database
}
return flag;
}
}
Here is test sample (using Moq). It shows you how you can return true from call to your mocked dependency:
[TestFixture]
class Tests
{
[Test]
public void AddAAATest()
{
// Arrange
Mock<ISecondDeep> secondDeep = new Mock<ISecondDeep>();
secondDeep.Setup(x => x.SomethingToDo(It.IsAny<string>())).Returns(true);
// Act
FirstDeep fd = new FirstDeep(secondDeep.Object);
// Assert
Assert.That(fd.AddA("ABD"), Is.EqualTo("ABCAAA"));
}
}

Categories

Resources