I have a unit test and am checking for null exceptions of my controller constructor for a few different services.
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
In my controller constructor I have:
if (routeCategoryServices == null)
throw new ArgumentNullException("routeCategoryServices");
if (routeProfileDataService == null)
throw new ArgumentNullException("routeProfileDataService");
I have a unit test for each, but how can I distinguish between the two. I can leave the test as is as either of the checks could be throwing null so I want to test the exception by param name.
Is this possible?
You could explicitly catch the exception in your test and then assert the value of the ParamName property:
try
{
//test action
}
catch(ArgumentException ex)
{
Assert.AreEqual(expectedParameterName, ex.ParamName);
}
Lee's answer is great, but the test will only fail if an ArgumentException is thrown with the wrong parameter name. If no exception is thrown, the test will pass. To remedy this, I added a bool in my test like this
// Arrange
var expectedParamName = "param";
bool exceptionThrown = false;
// Act
try
{
new Sut(null);
}
// Assert
catch (ArgumentNullException ex)
{
exceptionThrown = true;
Assert.AreEqual(expectedParamName, ex.ParamName);
}
Assert.That(exceptionThrown);
See this: http://msdn.microsoft.com/en-us/library/ms243315.aspx
You can provide the expected message too:
[TestMethod]
[ExpectedException(typeof(ArgumentNullException), "routeCategoryServices")]
Requires two test cases though.
var exception = Assert.Throws<ArgumentNullException>(() => new Sut(...));
Assert.That(exception.ParamName, Is.EqualTo("routeCategoryServices");
Related
Here is my unit test method
[Fact]
public void DealerSmsStatusTestTest_MustReturnInternalServerErrorIfMockMethodFails()
{
//Arrange
Mock<DBClass.IDealer> mock = new Mock<DBClass.IDealer>();
var exception = FormatterServices.GetUninitializedObject(typeof(System.Data.SqlClient.SqlException));
mock.Setup(x => x.GetDealerStatus(new System.Net.Http.HttpRequestMessage()))
.Throws((System.Data.SqlClient.SqlException)exception);
DealerSettingController controller = new DealerSettingController(mock.Object);
//Act
var result = controller.DealerSmsStatus();
//Assert
/*I will do assertion here*/
}
And here is my controller method
public IHttpActionResult DealerSmsStatus()
{
try
{
var result = _dealer.GetDealerStatus(Request);
return Json(new Models.Response(
Models.ResponseMessages.Success,
result)
);
}
catch (System.Data.SqlClient.SqlException)
{
return InternalServerError();
}
catch (System.Exception ex)
{
Logger.Error(ex, ex.Message, ex.StackTrace);
return InternalServerError();
}
}
When i debug the test, GetDealerStatus() method should return SqlException instead it returns null. In controller method var result always getting null. Any suggestions appreciated why it is not working.I want to throw SqlException through GetDealerStatus().
Here is debug mode result value image
You should use It.IsAny<System.Net.Http.HttpRequestMessage>() instead of new System.Net.Http.HttpRequestMessage() at Setup. Because you configured your method for concrete instance of System.Net.Http.HttpRequestMessage, at test it's not the same.
It's probably the matcher x.GetDealerStatus(new System.Net.Http.HttpRequestMessage())
new System.Net.Http.HttpRequestMessage() creates a new instance of a HttpRequestMessage which will not be equal to the Request you're passing into GetDealerStatus in your SUT.
Normally you'd use something like:
x.GetDealerStatus(It.IsAny<System.Net.Http.HttpRequestMessage>())
or
It.Is<System.Net.Http.HttpRequestMessage>(x => whatever specific equality conditions you want to match on)
if you want to narrow the match condition from just 'any'
I'm writing my first Unit test for very small project. Here the expected result and result both return a ArgumentNullException but the test still fails. Any idea why?
[TestMethod]
public void InsertFileBeginning_FilePathNull_ReturnArgumentNullException()
{
// Arrange
var generateFile = new GenerateFile();
string parameter = null; //pass FilePath Null
var expectedExcetpion = new ArgumentNullException();
// Act & Assert
var result = Assert.ThrowsException<ArgumentNullException>(() => generateFile.InsertFileBeginning(parameter));
Assert.AreEqual(expectedExcetpion, result);
}
------InsertFileBeginning function--------
public void InsertFileBeginning(string filePath)
{
try
{
using (var fs = new FileStream(filePath, FileMode.Create))
{
Byte[] metadata = new UTF8Encoding(true).GetBytes("THis is a test content");
fs.Write(metadata, 0, metadata.Length);
}
}
catch (Exception exception)
{
throw exception;
}
}
Error:
Expected: System.ArgumentNullException: Value cannot be null.
Actual: System.ArgumentNullException: Path cannot be null. Parameter name: path
Message: Assert.AreEqual failed. Expected:<System.ArgumentNullException: Value cannot be null.>. Actual:<System.ArgumentNullException: Path cannot be null.
Parameter name: path
at SmartTestSelecter.GenerateFile.InsertFileBeginning(String filePath) in C:\Users\CC\SmartTestSelecter\GenerateFile.cs:line 31
at SmartTestSelecterUnitTests.GenerateFileTest.<>c__DisplayClass0_0.<InsertFileBeginning_FilePathNull_ReturnArgumentNullException>b__0() in C:\Users\CC\STSUnitTests\GenerateFileTest.cs:line 21
at Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsException[T](Action action, String message, Object[] parameters)>.
Look at this;
var expectedExcetpion = new ArgumentNullException();
// Act & Assert
var result = Assert.ThrowsException<ArgumentNullException>(() => generateFile.InsertFileBeginning(parameter));
Assert.AreEqual(expectedExcetpion, result);
expectedException is an Object of type ArgumentNullException and result is also an object of type ArgumentNullException - however they're not the same object! you have 2 instances of the same type.
Now AreEqual(..) uses .Equals from what i could gather online.
I think that you're comparing the references of expectedException with result here. They are of course not the same. What you should instead do (if my assumptions are right) is check if the result is of the same type, rather than use AreEqual(..).
It seems you can use this method for that:
Assert.IsInstanceOfType
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.assert.isinstanceoftype?view=mstest-net-1.2.0
e.g.:
Assert.IsInstanceOfType(result, typeof(ArgumentNullException));
First of all, do not use [ExpectedException]. It turned out to be a bad practice because the exception can occur anywhere. And since you use Assert.ThrowsException, which does not throws the exception further, your test would fail anyway.
Secondly, I'm not quite up-to-date regarding MSTest but it seems it fails if the exception is not thrown with the default message. But if you can't specify the expected error message in Assert.ThrowsException, then you can implement your own assert method:
public static void Throws<T>(Action action, string expectedMessageContent = null)
where T : Exception
{
try
{
action.Invoke();
}
catch (Exception e)
{
Assert.IsInstanceOf(typeof(T), e);
Assert.IsTrue(expectedMessageContent == null
|| e.Message.Contains(expectedMessageContent), $"Expected message: {expectedMessageContent}{Environment.NewLine}Actual message:{e.Message}");
return;
}
Assert.Fail("No exception was thrown");
}
Disclaimer: I don't know whether MSTest has Assert.IsInstanceOf, etc methods but you see the point.
I am trying to unit test a method that throws an exception, and before throwing it has to perform a few tasks, like logging. I am using NSubstitute and can't get my head around this one.
so my test looks like this
[TestMethod]
[ExpectedException(typeof(IOException))]
public void RecordAnalyser_FileReadFailedInFirstAttempt_WarningLogged()
{
//Arrange
var fileMock = Substitute.For<IFile>();
fileMock.ReadLines(Arg.Any<string>()).Throws(new IOException());
//Act
var recordAnalyser = new RecordAnalyser(fileMock, logger); //--> throws exception.
//Assert
logger.Received(1).Warn(Arg.Any<string>(), Arg.Any<Exception>());
}
Now i want to assert if logger received a warning log, but since the line above sends an exception, and i have an expected exception attribute, test doesn't come to check for assertion.
One dirty code i can think of is to wrap the error statement in a try catch within the test, but its not the neatest.
//Act
try
{
var recordAnalyser = new RecordAnalyser(fileMock, logger);
}
catch (Exception)
{
// eat
}
Code under test -
public RecordAnalyser(IFile file, ILoggerService logger)
{
this.logger = logger;
try
{
names = file.ReadLines(Constants.Names).ToList();
}
catch (System.IO.IOException e)
{
logger.Error("Names file could not be read.", ex);
// How do I test above line without a try catch block in unit test
throw;
}
}
looking for suggestions here.
This may be an XY problem.
You are trying to test/assert multiple things in one test. hence the problem.
If the goal was just to test that the exception is thrown then great no try/catch and test would pass.
[TestMethod]
[ExpectedException(typeof(IOException))]
public void RecordAnalyser_Should_FailInFirstAttempt_When_FileRead() {
//Arrange
var fileMock = Substitute.For<IFile>();
fileMock.ReadLines(Arg.Any<string>()).Throws(new IOException());
//Act
var recordAnalyser = new RecordAnalyser(fileMock, logger); //--> throws exception.
}
In another test where you want to assert that something happens when the exception is thrown then you will need to catch the exception to allow the test to be exercised to completion and allow assertions to be verified.
[TestMethod]
public void RecordAnalyser_Should_LogWarning_When_FileReadFailedInFirstAttempt() {
//Arrange
var fileMock = Substitute.For<IFile>();
fileMock.ReadLines(Arg.Any<string>()).Throws(new IOException());
IOException error = null;
//Act
try {
var recordAnalyser = new RecordAnalyser(fileMock, logger); //--> throws exception.
} catch(IOException ex) {
error = ex; //catch and hold error for later
}
//Assert
if(error == null)
Assert.Failed("exception expected"); // error was not thrown.
logger.Received(1).Warn(Arg.Any<string>(), Arg.Any<Exception>());
}
You could use following Extension which provides the implementation of Assert.Throws(Action) and Assert.Throws(Action): https://github.com/bbraithwaite/MSTestExtensions
In the test below, if it enters the catch block I want to indicate that the test has passed. If the catch block is bypassed I want the test to fail.
Is there a way to do this, or am I missing the point with how tests should be structured?
[TestMethod]
public void CommandExecutionWillThrowExceptionIfUserDoesNotHaveEnoughEminence()
{
IUserCommand cmd = CreateDummyCommand("TEST", 10, 10);
IUser user = new User("chris", 40);
try
{
cmd.Execute(user);
}
catch(UserCannotExecuteCommandException e)
{
//Test Passed
}
// Test Failed
}
I tend to use this pattern when I have a similar situation:
// ...
catch (UserCannotExecuteCommandException e)
{
return; // Test Passed
}
Assert.Fail(); // Test Failed -- expected exception not thrown
Declare the test to throw UserCannotExecuteCommandException, when that happens the test will succeed
[ExpectedException( typeof( UserCannotExecuteCommandException) )]
I would suggest using Assert.Throws() method:
Assert.Throws<UserCannotExecuteCommandException>() => cmd.Execute(user));
Id does all what you need. It expect that an exception of type UserCannotExecuteCommandException would be thrown whilst execution of the cmd.Execute() method, otherwise automatially marks a test as failed.
Since [ExpectedException(...)] is concidered as a bad practice you might use:
MSTest: Assert.ThrowsException<UserCannotExecuteCommandException >( () => cmd.Execute(user) );
NUnit: Assert.Throws<UserCannotExecuteCommandException >( () => cmd.Execute(user) );
then you are able to point which line exactly should throw an exception.
How do I use Assert.Throws to assert the type of the exception and the actual message wording?
Something like this:
Assert.Throws<Exception>(
()=>user.MakeUserActive()).WithMessage("Actual exception message")
The method I am testing throws multiple messages of the same type, with different messages, and I need a way to test that the correct message is thrown depending on the context.
Assert.Throws returns the exception that's thrown which lets you assert on the exception.
var ex = Assert.Throws<Exception>(() => user.MakeUserActive());
Assert.That(ex.Message, Is.EqualTo("Actual exception message"));
So if no exception is thrown, or an exception of the wrong type is thrown, the first Assert.Throws assertion will fail. However if an exception of the correct type is thrown then you can now assert on the actual exception that you've saved in the variable.
By using this pattern you can assert on other things than the exception message, e.g. in the case of ArgumentException and derivatives, you can assert that the parameter name is correct:
var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null));
Assert.That(ex.ParamName, Is.EqualTo("bar"));
You can also use the fluent API for doing these asserts:
Assert.That(() => foo.Bar(null),
Throws.Exception
.TypeOf<ArgumentNullException>()
.With.Property("ParamName")
.EqualTo("bar"));
or alternatively
Assert.That(
Assert.Throws<ArgumentNullException>(() =>
foo.Bar(null)
.ParamName,
Is.EqualTo("bar"));
A little tip when asserting on exception messages is to decorate the test method with the SetCultureAttribute to make sure that the thrown message is using the expected culture. This comes into play if you store your exception messages as resources to allow for localization.
You can now use the ExpectedException attributes, e.g.
[Test]
[ExpectedException(typeof(InvalidOperationException),
ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
MethodA(null);
}
Assert.That(myTestDelegate, Throws.ArgumentException
.With.Property("Message").EqualTo("your argument is invalid."));
A solution that actually works:
public void Test() {
throw new MyCustomException("You can't do that!");
}
[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
var exception = Assert.ThrowsException<MyCustomException>(
() => Test(),
"This should have thrown!");
Assert.AreEqual("You can't do that!", exception.Message);
}
This works with using Microsoft.VisualStudio.TestTools.UnitTesting;.
For those that are using the NUnit 3.0 Constraint Model and ended up here:
Assert.That(() => MethodUnderTest(someValue), Throws.TypeOf<ArgumentException>());
To expand on persistent's answer, and to provide more of the functionality of NUnit, you can do this:
public bool AssertThrows<TException>(
Action action,
Func<TException, bool> exceptionCondition = null)
where TException : Exception
{
try
{
action();
}
catch (TException ex)
{
if (exceptionCondition != null)
{
return exceptionCondition(ex);
}
return true;
}
catch
{
return false;
}
return false;
}
Examples:
// No exception thrown - test fails.
Assert.IsTrue(
AssertThrows<InvalidOperationException>(
() => {}));
// Wrong exception thrown - test fails.
Assert.IsTrue(
AssertThrows<InvalidOperationException>(
() => { throw new ApplicationException(); }));
// Correct exception thrown - test passes.
Assert.IsTrue(
AssertThrows<InvalidOperationException>(
() => { throw new InvalidOperationException(); }));
// Correct exception thrown, but wrong message - test fails.
Assert.IsTrue(
AssertThrows<InvalidOperationException>(
() => { throw new InvalidOperationException("ABCD"); },
ex => ex.Message == "1234"));
// Correct exception thrown, with correct message - test passes.
Assert.IsTrue(
AssertThrows<InvalidOperationException>(
() => { throw new InvalidOperationException("1234"); },
ex => ex.Message == "1234"));
Since I'm disturbed by the verbosity of some of the new NUnit patterns, I use something like this to create code that is cleaner for me personally:
public void AssertBusinessRuleException(TestDelegate code, string expectedMessage)
{
var ex = Assert.Throws<BusinessRuleException>(code);
Assert.AreEqual(ex.Message, expectedMessage);
}
public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception
{
var ex = Assert.Throws<T>(code);
Assert.AreEqual(ex.Message, expectedMessage);
}
The usage is then:
AssertBusinessRuleException(() => user.MakeUserActive(), "Actual exception message");
I recently ran into the same thing, and suggest this function for MSTest:
public bool AssertThrows(Action action) where T : Exception
{
try {action();
}
catch(Exception exception)
{
if (exception.GetType() == typeof(T))
return true;
}
return false;
}
Usage:
Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); }));
There is more in Assert that a particular exception has occured (Assert.Throws in MSTest).
Asserting exception :
In Junit 5 :
#Test
public void whenExceptionThrown_thenAssertionSucceeds() {
Exception exception = assertThrows(NumberFormatException.class, () -> {
Integer.parseInt("1a");
});
String expectedMessage = "For input string";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
}
In Junit 4:
#Test(expected = NullPointerException.class)
public void whenExceptionThrown_thenExpectationSatisfied() {
String test = null;
test.length();
}