Xunit to return a new argument - c#

I am new to Xunit. I throw a new exception in my code :
throw new NotImplementedException("Missing UPC. File is corrupt");
in my test file I wrote:
[Fact]
public void ParserRow_Throws_Exception_For_Null_UPC()
{
var record = GetRessoRecord();
record.UPC = "";
RevenueReportItem result = Sut.ParseRow(record);
Assert.Throws<NotImplementedException>(() => Sut.ParseRow(record));
}
The error message in the Test Explorer says
System.NotImplementedException : Missing UPC. File is corrupt
How do I add in the returned quote?

The synchronous variant of Throws<> is now obsolete.
You're calling the tested method twice. Remove the first call that's outside of the assert, as it will throw the exception and halt test execution.
The call to Throws<> returns the exception object, from which you can retrieve and check the message, like so:
[Fact]
public async Task ParserRow_Throws_Exception_For_Null_UPC()
{
var exceptionDetails = await Assert.ThrowsAsync<NotImplementedException>(() => {
throw new NotImplementedException("foo");
});
Assert.Equal("foo", exceptionDetails.Message);
}

Related

How to verify method was reached if throw before

I have my method as below which adds new user to database when such user name doesn't exist in database. If user name exist it throws custom exception therefore addUserType method is not reached.
public void CreateUserType(UserType userType)
{
if (userType == null) throw new ApplicationException("UserType object cannot be null");
if (_bottleClientQuery.IsUserTypeExist(userType.Name)) throw new ApplicationException("Such user type name already exist");
_bottleClientRepository.AddUserType(userType);
}
My testing methods are as shown below:
This method correctly giving me the expected result:
[Test]
public void CreateUserType_UserTypeExists_ThrowsApplicationException()
{
UserQuery.Setup(uow => uow.IsUserTypeExist(It.IsAny<string>())).Returns(true);
Assert.Throws<Exceptions.ApplicationException>(() => CreateClientService.CreateUserType(new UserType()));
}
Nevertheless in this method i want to check whether AddUserType was reached or not. I setup it as IsUserTypeExist returns true which means such user name exist therefore
AddUserType will be not reached.
[Test]
public void CreateUserType_UserTypeExists_AddUserTypeRepositoryNotReached()
{
UserQuery.Setup(uow => uow.IsUserTypeExist(It.IsAny<string>())).Returns(true);
CreateClientService.CreateUserType(new UserType());
UserRepository.Verify(uow => uow.AddUserType(It.IsAny<UserType>()),Times.Never);
}
The problem with second test method is the ApplicationException is thrown (that's fully fine and expected) but i would really like to test whether AddUserType was not reached.
Is it possible when before thrown exception was there?
You could change your test method to something like this;
[Test]
public void CreateUserType_UserTypeExists_AddUserTypeRepositoryNotReached()
{
UserQuery.Setup(uow => uow.IsUserTypeExist(It.IsAny<string>())).Returns(true);
Assert.Throws<ApplicationException>(() => CreateClientService.CreateUserType(new UserType()));
UserRepository.Verify(uow => uow.AddUserType(It.IsAny<UserType>()),Times.Never);
}
This will both verify that the expected exception is thrown and ensure that execution continues to your next verification.

Exception message in xunit includes parameter so my test fails

I am trying to check that an exception that I throw gives the correct error message.
I have a method in a class that withdraws (substracts) from a value. If the value is less than 0, I throw an exception.
if (amount < 0)
{
throw new System.ArgumentOutOfRangeException("amount", AmountLessThanZeroMessage);
}
This is my error message:
public const string AmountLessThanZeroMessage = "Amount is less than zero";
However, when I try to write a unit test to see if I get the correct message, it fails because of the parameter. This is the test:
[Fact]
public void CannotWithdrawLessThanZero()
{
// Arrange
var account = new Account("User", 23);
// Act
account.DepositCash(100);
var thrownException = Assert.Throws<ArgumentOutOfRangeException>(() => account.WithdrawCash(-10));
// Assert
Assert.Equal(Account.AmountLessThanZeroMessage, thrownException.Message);
}
The result includes the parameter in the end, resulting in a failed test:
It seems the actual message includes which parameter it refers to. How do I correct this message? Should I just add the line (Parameter 'amount') to the expected string, or are there any better options?
You can create the exact same exception and use its message property. Like the code below
[Fact]
public void CannotWithdrawLessThanZero()
{
// Arrange
var account = new Account("User", 23);
var expectedException = new System.ArgumentOutOfRangeException("amount", AmountLessThanZeroMessage);
// Act
account.DepositCash(100);
var thrownException = Assert.Throws<ArgumentOutOfRangeException>(() => account.WithdrawCash(-10));
// Assert
Assert.Equal(expectedException.Message, thrownException.Message);
}
Messages changes often, message can be localized, so testing message equality will make tests more fragile.
Instead you can test that correct exception type was thrown, or even better and create domain specific exception to be sure that exception have been thrown for correct reasons.
public class WithdrawOfNegativeAmountNotAllowedException : Exception
{
public WithdrawOfNegativeAmountNotAllowedException(int amount)
: base($"Amount is less than zero ({amount})")
{
}
}
[Fact]
public void Cannot_withdraw_less_than_zero()
{
var account = new Account("User", 23);
account.DepositCash(100);
Action withdraw = () => account.WithdrawCash(-10);
withdraw.Should().Throw<WithdrawOfNegativeAmountNotAllowedException>();
}
In case you still want to test for correct message. Assertions of strings can be done in multiple ways, I would suggest to make assertion as loose as possible.
Test for part of the message which unlikely will change. For example test that message starts with some text or contain critical value.
[Fact]
public void Cannot_withdraw_less_than_zero()
{
var account = new Account("User", 23);
account.DepositCash(100);
Action withdraw = () => account.WithdrawCash(-10);
withdraw.Should()
.Throw<WithdrawOfNegativeAmountNotAllowedException>()
.And
.Message.Should().ContainEquivalentOf("Amount is less than zero");
}

How to user Assert for methods with return type void in MSTest

I have a method in my c# application similar to below.
public async Task SampleMethod()
{
try
{
//some code
await AnotherMethod();
// some code
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message.ToString());
}
}
Now, I'm trying to write a unit testcase for the above method using MStest. I have written something as below.
[TestMethod]
public async Task SampleMethodTest()
{
ClassName cn = new ClassName();
await cn.SampleMethod();
}
Now how do I know if the testcase failed or succeeded. How do I use Assert here?
Any help is highly appreciated.
Based on our comments in my other answer, i try to show you how to get the console output. That you can read all text from console you have to set a StringWriter() to the console:
[TestMethod]
public async Task SampleMethodTest()
{
using (StringWriter stringWriter = new StringWriter())
{
Console.SetOut(stringWriter);
ClassName cn = new ClassName();
await cn.SampleMethod();
string consoleOutput = stringWriter.ToString();
Assert.IsFalse(consoleOutput.Contains("Exception"));
}
}
I hope this works. I haven't tried it with a UnitTest, only with a console program.
If you test the AnotherMethod directly, you will see if it's succefull. When it throws an Exception the test is failed. The SampleMethod does only implement the try catch and calls the AnotherMethod() which can be tested directly.
[TestMethod]
public async Task SampleMethodTest()
{
ClassName cn = new ClassName();
await cn.AnotherMethod();
}
This test fail if it throws an Execption. When the method do not throw an Exception, it is successfull.
If your method changes the state of the object, you can verify if the state of the object is like expected. If not you can use a Mock (with a Framework like Moq) to verify the collaboration with other objects. Note that you maybe need to extract AnotherMethod to another class, so that you can mock and verify the call.
Also note that you should try to design your Software so that you can use Outputverification and Stateverification in most UnitTests. Communication Verification with mocks can lead to false postives and UnitTests that are hard to maintain.

Async unit testing with NUnit and C#

I have the following method I created it's nothing fancy just retrieves data from an HTTP server but it is an async method.
public async Task<string> GetStringFromConsul(string key)
{
string s = "";
// attempts to get a string from Consul
try
{
//async method to get the response
HttpResponseMessage response = await this.http.GetAsync(apiPrefix + key);
//if it responds successfully
if (response.IsSuccessStatusCode)
{
//parse out a string and decode said string
s = await response.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<List<consulValue>>(s);
s = Encoding.UTF8.GetString(Convert.FromBase64String(obj[0].value));
}
else
{
s = requestErrorCodePrefix + response.StatusCode + ">";
}
}
catch(Exception e)
{
//need to do something with the exception
s = requestExceptionPrefix + e.ToString() + ">";
}
return s;
}
Then in the test I call the code just like I do during normal execution:
[Test]
public async Task GetStringFromConsulTest()
{
ConsulConfiguration cc = new ConsulConfiguration();
string a = cc.GetStringFromConsul("").GetAwaiter().GetResult();
Assert.AreEqual(a, "");
}
However I get an exception like so instead of any sort of string:
Message: Expected string length 514 but was 0. Strings differ at index 0.
Expected: "<Request Exception: System.Threading.Tasks.TaskCanceledExcept..."
But was: <string.Empty>
I've looked around and found a few tutorials on this and tried it but to no avail. If anyone can point me in the right direction I would appreciate it, I'm pretty new to C# unit testing.
I'm a stickler for good error messages so I'd first change the assert to
Assert.AreEqual("", a);
because the first argument is your expected value. Now it will fail with
Message: Expected string length 0 but was 514. Strings differ at index 0.
Expected: <string.Empty>
But was: "<Request Exception: System.Threading.Tasks.TaskCanceledExcept..."
...still a failure, but a much more sensible message.
Next, to pass, add an await to your async method call, as suggested by M Hassan.
In Nunit Framework, Use async/await in unit test as in the following:
[Test]
public async Task GetStringFromConsulTest()
{
ConsulConfiguration cc = new ConsulConfiguration();
//string a = cc.GetStringFromConsul("").GetAwaiter().GetResult();
//use await instead
string a = await cc.GetStringFromConsul("");
Assert.AreEqual(a, "");
}
For more details, read Async Support in NUnit
It's better to test your method in case of firing exceptions NUnit expected exceptions
Update:
The comment:
I still get the error even when structuring the method like this.
That error means that the test fail and there is a bug in the source code method GetStringFromConsul.
Your test method include the Assert statement:
Assert.AreEqual(a, "");
That means that you expect a variable which is calculated from a=cc.GetStringFromConsul("") should be "" to pass,
otherwise the test fail and NUnit Framework Fire an exception like:
Message: Expected string length 514 but was 0. Strings differ at index 0.
Expected: "<Request Exception: System.Threading.Tasks.TaskCanceledExcept..."
But was: <string.Empty>
To resolve this exception, you should resolve the bug in the method GetStringFromConsul to return "" when the input parameter=""
Maybe this.http.GetAsync(apiPrefix + key); is timing out. That would give you a TaskCanceledException. Not sure what your value of apiPrefix is.

Create and pass a action/delegate of a method at runtime to TaskFactory.StartNew method

I need to create and pass a action/delegate of a method at runtime to TaskFactory.Satrtnew method. In general I would do the following when i know the method to use.
public void SomeService(CancellationToken cToken)
{ }
var tasks = new Task[] {
Task.Factory.StartNew(() => SomeService(new CancellationToken())
};
In my case, when I to do this at runtime, where my method names comes from configuration file. The method exists but it would be assigned to task at runtime. I tried something like
var conn = bll.daService.DbConnection;
var currentType = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;
var method = currentType.GetMethod("SomeService");
Action<CancellationToken> action = (Action<CancellationToken>)
Delegate.CreateDelegate(typeof(Action<CancellationToken>),currentType,method);
Task.Factory.StartNew(action);
And also something like.
delegate void ServiceDelegate(CancellationToken cToken);
ServiceDelegate serDel = (ServiceDelegate)
Delegate.CreateDelegate(currentType,method);
Action ac = serDel(new CancellationToken());
Task.Factory.StartNew(ac);
None of them are working.It throws different kind of errors and exceptions.
EDIT: The following line throws exception "Type must derive from Delegate"
ServiceDelegate serDel = (ServiceDelegate)
Delegate.CreateDelegate(currentType,method)

Categories