How to verify method was reached if throw before - c#

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.

Related

Xunit to return a new argument

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

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

Selenium C# continue on failure

I'm trying to learn automation with Selenium Webdriver using c#. I have my custom method Assert. What I did to continue the test after catching an AssertFailedException is using try-catch below is my code
public static void assert(string value, IWebElement element)
{
try
{
Assert.AreEqual(value, element.Text);
}
catch (AssertFailedException e)
{
Console.WriteLine(e.Message.ToString());
}
}
My problem is it catches all AssertFailedException(which is my goal) but the result of the test is PASSED in visual studio. My question is, how do I implement Continue on Failure and Fail the test if the Console contains Exceptions. Thankyou in advance guys!
As far as I understand, you want to do several checks inside your test, and at the very end of it to determine whether any of of them failed. You may need to write some custom code to achieve this. For example, you may introduce a class Assertion:
internal class Assertion
{
private readonly string title;
private readonly object expected;
private readonly object actual;
public Assertion(string title, object expected, object actual)
{
this.title = title;
this.expected = expected;
this.actual = actual;
}
public bool IsMatch()
{
return this.actual == this.expected;
}
public override string ToString()
{
return $"Title: {title}. Expected: {expected}. Actual: {actual}";
}
}
When your test is running, you will create new instances of Assertion class and store them in a list. At the end of the test, you can use the following method:
private static void VerifyAssertions(Assertion[] assertions)
{
var failedAssertions = assertions.Where(a => !a.IsMatch()).ToArray();
if (failedAssertions.Any())
{
throw new AssertFailedException(string.Join<Assertion>("; ", failedAssertions));
}
}
You could try using verify instead of assert for minor checks. Assert by default indicates a major checkpoint and script execution will be terminated on fail and if you catch that exception the reporting will be ignored - this is expected behaviour. However, a verify indicates that the script can continue even on fail - in this case the failed step will be reported and the script will continue.
To put it simply, use assert when you don't want the script to proceed on failure and use verify when you want the script to report the failure and proceed.

Check if Action input parameter is null

I have a method with the signature below. I put in checks to make sure that the inputs are not null. However, with input parameters that are an Action it is always seeing the input as null. What is a better way to perform this check for inputs that are of Action Type?
Any suggestions would be appreciated.
public void DeleteTreeValue(TreeValue treeValue, Action<Exception> callback)
{
if (treeValue == null)
throw new ArgumentNullException("treeValue");
//This is always throwing the ArugmentNullException even when the callback is passed
if (callback == null)
throw new ArgumentNullException("callback");
EDIT: Here is an example of how it is being called. I can see the method in the call back when I debug it, but this could still be seen as null in the arg check which is probably what is happening.
[Test]
public void DeleteValueShouldThowExceptionWhenValueDoesNotExist()
{
var myValue = new TreeValue {TreeValueId = -1};
_dataService.DeleteTreeValue(myValue, exception =>
{
Assert.IsNotNull(exception);
});
}

Verifying a method call still passes when a failure is expected in unit test

I've just started playing around with Moq in my unit tests, but am having an issue where the unit test is passing - and I don't think it should be.
I have two objects, one that despatches data to a queue and another that implements INotifier which is called if the despatcher fails, they look like this (cut down for brevity):
public class EmailNotifier : INotifier
{
public void Notify(string message)
{
// sends the notification by email
}
}
public class Despatcher
{
public void Despatch(int batchNumber, INotifier failureNotifier)
{
try
{
if (batchNumber.Equals(0)) throw new InvalidOperationException("Error message");
}
catch (InvalidOperationException ex)
{
failureNotifier.Notify(ex.ToString());
throw ex;
}
}
}
I am unit testing the Despatcher to specifically verify that Notify is being called on the provided INotifier (which I'm mocking) when it fails (I'm intentionally forcing the Despatcher to fail by passing a 0 batch number). I set up my mocks like this:
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void Despatcher_notifies_on_failure()
{
var mockNotifier = new Mock<EmailNotifier>();
mockNotifier.Setup(n => n.Notify(It.IsAny<string>())).Verifiable();
var despatcher = new Despatcher();
despatcher.Despatch(0, mockNotifier.Object);
mockNotifier.Verify(n => n.Notify(It.IsAny<string>()), Times.Once());
}
This passes the test fine, which is expected as a 0 batch number raises the exception which causes the INotifier to call Notify (when I step through the test everything works as expected).
So, I go on to comment out the failureNotifier.Notify(ex.ToString()) line and run the test again - passes fine? I'm not sure whether I'm setting up and verifying correctly as I've only been using Moq for about 2 hours now but I thought I was understanding this correctly, but this has just thrown me a bit. I expect this test to fail as I specifically want to make sure Notify is called in the event of a failure - can anyone see anything obviously wrong here? Thanks in advance for your help as always.
Your test never gets to the verification part. Why? This line
despatcher.Despatch(0, mockNotifier.Object);
Throws exception, which is consumed by ExpectedException attribute and test ends. The mockNotifier.Verify line is never executed.
What you want is two unit tests, instead:
one testing that notifier is called upon exception (with .Verify). Note that you'll have to wrap .Despatch call into try { } catch { }, so that exception is ignored.
second, checking that exception is rethrown (with ExpectedException)

Categories