MSTest Unit Test asserting specific exception messages - c#

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.

Related

How do I assert against a Boolean value to confirm that causes an exception to be thrown in C#?

I'm writing my unit tests for my application and I'm trying to make sure that an exception is throw in one of my services. That exception is throw based on a true/false condition but I'm not sure how to get it to work. I am using NSubstitute for mocking in my unit tests and MSTest for the testing framework.
Here is my unit test.
private readonly FileRepository _sut;
private readonly BlobServiceClient _blobServiceClient = Substitute.For<BlobServiceClient>();
private readonly BlobContainerClient _blobContainerClient = Substitute.For<BlobContainerClient>();
private readonly BlobClient _blobClient = Substitute.For<BlobClient>();
public BlobStorageFileRepositoryTests()
{
_blobServiceClient.GetBlobContainerClient(default).ReturnsForAnyArgs(_blobContainerClient);
_blobContainerClient.GetBlobClient(default).ReturnsForAnyArgs(_blobClient);
_sut = new FileRepository(_blobServiceClient);
}
[TestMethod]
[ExpectedException(typeof(Exception), "file already")]
public async Task PlaceFileInStorage_ShouldReturnErrorIfFileExists()
{
// Arrange
var fileName = "myfile.pdf";
// Act
_sut.CheckFileExists(fileName).Returns(true);
}
As you can see the test method is decorated with the expected exception type and the message we expect to see. The error I get when I attempt to run this test is:
Test method threw exception NSubstitute.Exceptions.CouldNotSetReturnDueToTypeMismatchException, but exception System.Exception was expected. Exception message: NSubstitute.Exceptions.CouldNotSetReturnDueToTypeMismatchException: Can not return value of type Task`1 for Response`1.get_Value (expected type Boolean).
This makes sense as I am returning a boolean when I declare CheckFileExists but I want to know how I can access the thrown error that occurs when the boolean is false. Here is the service itself so you can see the construction of this method.
public async Task PlaceFileInStorage(string fileName, byte[] data)
{
//Check if the file exists first
var fileCheck = await CheckFileExists(fileName);
var file = fileName.Insert(0, DateTime.UtcNow.ToString("yyyy-MM-dd-HH:mm:ss"));
if (fileCheck.Equals(false))
{
try
{
var blob = _container.GetBlobClient(fileName);
await using var ms = new MemoryStream(data, false);
await blob.UploadAsync(ms, CancellationToken.None);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
throw new Exception("This file already exists");
}
You can see above that it checks if the files exists in storage first and then we either save or return an exception based on that. So, in my unit test how can I check that the exception is thrown when the fileCheck condition is true?
Many thanks
I am not sure how NSubstitue works, but you're clearly receiving an exception because the mock you're trying to do is incorrect, hence your test fails because is NSubstitute who throws the exception, not your FileRepository class.
Now, if you want to check whether a tested method returns an exception of the expected type, you can use the Assert class:
Assert.ThrowsExceptionAsync<Exception>(async () => await _sut.PlaceFileInStorage(filename, data));
This assert will succeed only if the exception throw is of the type you specify.
Here you have the reference for this method: https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.assert.throwsexceptionasync?view=visualstudiosdk-2022#microsoft-visualstudio-testtools-unittesting-assert-throwsexceptionasync-1

Mock function not throwing exception in c# unit test

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'

unit testing for ArgumentNullException by param name

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

Checking if argument is thrown in unit-tests

I'm working on unit-tests for an application which has a constructor that takes three values as arguments. The numbers shall be 0 or higher, and now I'm writing on an unit-test for the constructor that throws an exception if this is not the case.
What I can't figure out is how I what to write after "Assert" to determine this so that the test passes if illegal numbers are passed to the constructor. Thanks in advance.
EDIT: I'm using MSTest framework
public void uniqueSidesTest2()
{
try {
Triangle_Accessor target = new Triangle_Accessor(0, 10, 10);
}
catch (){
Assert // true (pass the test)
return;
}
Assert. // false (test fails)
}
// From the code...
public Triangle(double a, double b, double c) {
if ((a <= 0) || (b <= 0) || (c <= 0)){
throw new ArgumentException("The numbers must higher than 0.");
}
sides = new double[] { a, b, c };
}
First of all, you should throw an ArgumentOutOfRangeException rather than just an ArgumentException.
Second, your unit test should expect an Exception to be thrown, like so:
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public static void MyUnitTestForArgumentA()
{
...
}
So, you need to create separate unit tests -- one for each argument -- that test whether the method throws a correct exception when the argument is out of range.
No need to use a try catch block. Using NUnit or the MSTest framework you can use an attribute on your test method declaration to specify that you expect an exception.
MSTest
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void uniqueSidesTest2()
It may not be the best solution, but if I'm testing to make sure an Exception is thrown, I will do something like the following:
public void uniqueSidesTest2()
{
try {
Triangle_Accessor target = new Triangle_Accessor(0, 10, 10);
Assert.Fail("An exception was not thrown for an invalid argument.");
}
catch (ArgumentException ex){
//Do nothing, test passes if Assert.Fail() was not called
}
}
Since your constructor call should throw an error, if it ever gets to the second line (The Assert.Fail() line) then you know it didn't properly throw the exception.
If you don't have nunit (or other framework that has this support built in you can use the following type of helper method
public static void ThrowsExceptionOfType<T>(Action action) where T: Exception
{
try
{
action();
}
catch (T)
{
return;
}
catch (Exception exp)
{
throw new Exception(string.Format("Assert failed. Expecting exception of type {0} but got {1}.", typeof(T).Name, exp.GetType().Name));
}
throw new Exception(string.Format("Assert failed. Expecting exception of type {0} but no exception was thrown.", typeof(T).Name));
}
Your test would look like this
AssertHelper.ThrowsExceptionOfType<ArgumentException>(
() =>
{
new Triangle_Accessor(0, 10, 10);
});
You will not need an Assert in the catch (but you might want to catch a more specific exception, like ArgumentException).
To always fail, there is an Assert.Fail.
You don't mention what framework you are using for unit testing, but I think what you're looking for is something like what is shown here:
http://www.nunit.org/index.php?p=exception&r=2.4

How do I use Assert.Throws to assert the type of the 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();
}

Categories

Resources