Fetch Program ApplicationExitCode for Unit Test - c#

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);

Related

How to get passing parameter count in a function NUNIT mocking assertion?

How to get the parameters count which is passing to the function using Nunit mocking for assertion and that function called inside another function.
For e.g:
public class TestClass
{
public string Name {get;set;}
public int Id {get;set;}
}
public void ProcessData(IEnumerable<EventData> events)
{
List<TestClass> testClasses = new();
events.ForEach(msg => {
var testClass = JsonConvert.DeserializeObject<TestClass>(msg.EventBody.ToString());
if(testClass != null)
{
testClasses.Add(testClass);
}
});
if(testClasses.Count > 0)
{
BulkUpdateData(testClasses);
}
}
public void BulkUpdateData(List<TestClass> testClasses)
{ ... }
Now, I need to do unit testing this "ProcessData" method.
For this using NUnit framework in .Net 6.0.
I can pass test data to "ProcessData" method by mocking while writing unit test cases.
But here my case is,
Consider now I'm passing 10 values in a list to "ProcessData". In that only 8 got passed to "BulkUpdateData" method since 2 values are not got deserialized due to invalid data.
Here how to get this BulkUpdateData got 8 values inside the "ProcessData" method.
I need to get this count value for assertion.
Kindly suggest on this.
Your ProcessData() method needs to return something. Either an int representing the count of processed testclasses, or List<TestClass>.
With your ProcessData() method now returning something, you can then go ahead and write your asserts, knowing exactly how many testclasses were passed to BulkUpdateData() method.
public IEnumerable<TestClass> ProcessData(IEnumerable<EventData> events)
{
List<TestClass> testClasses = new();
events.ForEach(msg => {
var testClass = JsonConvert.DeserializeObject<TestClass>(msg.EventBody.ToString());
if (testClass != null)
{
testClasses.Add(testClass);
}
});
if (testClasses.Count > 0)
{
BulkUpdateData(resultOfProcessData);
}
return testClasses;
}
If I misunderstood your question and actually, you want to unit test BulkUpdateData() method, in your [TestFixture] you could add an instance variable to hold either the count or the list of TestClass objects. And you could take advantage of the [OrderAttribute] and organize your tests like this:
[TestFixture]
public class UnitTests
{
List<TestClass> resultOfProcessData = new();
[Test]
[Order(1)]
public void ProcessDataUnitTest()
{
resultOfProcessData = ProcessData(events);
}
[Test]
[Order(2)]
public void BulkUpdateDataUnitTest()
{
if (resultOfProcessData.Count > 0)
{
BulkUpdateData(resultOfProcessData);
}
}
public IEnumerable<TestClass> ProcessData(IEnumerable<EventData> events)
{
List<TestClass> testClasses = new();
events.ForEach(msg => {
var testClass = JsonConvert.DeserializeObject<TestClass>(msg.EventBody.ToString());
if (testClass != null)
{
testClasses.Add(testClass);
}
});
return testClasses;
}
public void BulkUpdateData(List<TestClass> testClasses)
{ ... }
}
Hope this helps.

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.

Testing async method does not give consistent result

I am trying to figure out the reason why my unit test would fail when run together with other unit tests in the solution but pass when run alone. Can anyone show me what am I missing?
The SUT is a class called CompositeClient that is essentially a wrapper class around two other clients. It's main idea is to give priority to one of those clients to be called.
public class CompositeClient : IReceiverChannel
{
private static readonly List<IReceiverChannel> ReceiverChannels = new List<IReceiverChannel>();
public CompositeClient(IReceiverChannel priority, IReceiverChannel normal)
{
ReceiverChannels.Add(priority);
ReceiverChannels.Add(normal);
}
public async Task<IEnumerable<Request>> ReceiveBatchAsync(int batchSize)
{
var req = new List<Request>();
foreach (var channel in ReceiverChannels)
{
req.AddRange(await channel.ReceiveBatchAsync(batchSize - req.Count).ConfigureAwait(false));
if (req.Count >= batchSize)
{
break;
}
}
return req;
}
}
Running the unit test below with all the other unit tests in the solution yield me a failed result. But if I run this test alone, it will pass.
[TestMethod]
public async Task ReceivedRequestShouldComeFromPriorityClientFirst()
{
var normalPriorityClient = GetNormalClientMock();
var highPriorityClient = GetPriorityClientMock();
var compositeClient = new CompositeClient(highPriorityClient, normalPriorityClient);
var requests = await compositeClient.ReceiveBatchAsync(1);
requests.Should().HaveCount(1);
requests.First().Origin.Should().BeSameAs("priority");
normalPriorityClient.CallCount.Should().Be(1); // It will fail here with actual CallCount = 0.
highPriorityClient.CallCount.Should().Be(0);
}
private static ReceiverChannelMock GetNormalClientMock()
{
return new ReceiverChannelMock("normal");
}
private static ReceiverChannelMock GetPriorityClientMock()
{
return new ReceiverChannelMock("priority");
}
private class ReceiverChannelMock : IReceiverChannel
{
private readonly string name;
public ReceiverChannelMock(string name)
{
this.name = name;
}
public int CallCount { get; private set; }
public Task<IEnumerable<Request>> ReceiveBatchAsync(int batchSize)
{
this.CallCount++;
return Task.FromResult<IEnumerable<Request>>(
new List<Request>
{
new Request
{
Origin = this.name
}
});
}
}
Tools used:
Visual Studio 2013
.NET Framework 4.5.2
Resharper 9.2
FluentAssertion
As David pointed out, I overlooked the static field that I declared in the CompositeClient class. Removing the static keyword solved the issue.

How to write test case for Run time Assembly Location

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]);
}
}

MOQ - How to verify static class call and delegates?

I just started reading on Moq framework and thought of applying it to my existing code. I could come up with a test case to verify basic function calls. But now stuck at applying it to delegates and static classes.
Below is the system under test (SUT)
public class SUT : ISUT
{
private IInterface1 i1;,
private IInterface2 i2;
public SUT(IInterface1 i1, IInterface2 i2)
{
this.i1 = i1;
this.i2 = i2;
}
public void FunctionToTest(Action<string> someDelegate, Action otherDelegate)
{
var list = i2.GetList();
foreach(var r in list)
{
i1.SomeFunction(r);
if(someDelegate != null)
someDelegate("message");
SomeHelper.LogData(r);
}
if(otherDelegate != null)
otherDelegate();
}
}
I have setup my test as below
[TestFixture]
public class when_list_contains_atleast_one_item
{
ISUT sut;
Mock<IInterface1> mockI1;
Mock<IInterface2> mockI2;
public SUT_Tester()
{
mockI1 = new Mock<IInterface1>();
mockI2 = new Mock<IInterface2>();
sut = new SUT(mockI1.Object, mockI2.Object);
}
[Test]
public void it_should_call_somefunction_calldelegates_and_log_data()
{
var dummyList = new List<string> { "string1", "string2" };
mockI2.Setup(m2 => m2.GetList()).Returns(dummyList).Verifiable();
sut.FunctionToTest(It.IsAny<Action<string>>(), It.IsAny<Action>());
// How to verify delegates were raised
// How to verify SomeHelper.LogData was called
mockI1.Verify(m => m.SomeFunction(It.IsAny<string>()), Times.Exactly(2));
mockI2.Verify();
}
}
How to verify that someDelegate and otherDelegate were raised ?
SomeHelper is a static class and LogData is a static function. How to verify that LogData was called?
Below is the SomeHelper class
public static class SomeHelper
{
static ILogger logger = LoggerManager.GetLogger("Something");
public static void LogData(string input)
{
logger.Info(input);
}
}
You cannot verify static methods since they cannot be mocked by Moq.
In order to verify calls on the delegates, create them so that they call a local function and you keep the state and verify:
string localString = string.Empty;
Action<string> action = (string s) => localString = s;
// ... pass it to the test
Assert.(localString == "TheStringItMustbe");
(UPDATE)
OK to check an action that has no in params, increment a local variable and assert if it has been incremented (or something similar):
int localVar = 0;
Action action = () => localVar++;
// ... pass it to the test
Assert.(localVar == 1);
You might want to consider changing the IInterface1/2 interfaces so that they either take an ILogger as a parameter into SomeFunction, or have a settable ILogger property.
Then you could pass a mocked ILogger into SomeFunction.

Categories

Resources