Moq - Verify Exception Was Thrown

Unit testing, using Moq to verify the exception message

It doesn't match because the two exceptions you compare aren't the same instance of Exception.

You can check if the message part of the Exception is what you want by passing in a lambda expression like this

services.MockLogProvider.Verify(x => x.LogExceptionAsync(
It.Is<Exception>(e => e.Message == "Order doesn't exist on ERP"),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<Dictionary<string, string>>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<int>()));

Moq fails to throw exception in Unit Test

If an invoked mock does not behave as expected, most times it is because the setup did not match what was actually invoked.

Consider loosening the expectation using It.IsAny<T>()

Fact(DisplayName = "AddUserSettingsAsync - InvalidOperationException")]
[Trait("Category", "Unit Test")]
public async Task SettingsStoreAddUserSettingsTestWithException() {
//Arrange
string userObject = Guid.NewGuid().ToString();
string correlationId = Guid.NewGuid().ToString();

string body = File.ReadAllText("TestData/userSettings.json");
UserSettingsObject userSettingsObject = JsonConvert.DeserializeObject<UserSettingsObject>(body);

var iFunctionEnvironment = TestHelpers.GetEnvironmentVariable("Test");

Uri.TryCreate("http://localhost", UriKind.Absolute, out Uri uri);

var iblobStorageRepositoryMoq = new Mock<IBlobStorageRepository>();
iblobStorageRepositoryMoq
.Setup(mock => mock.Add(It.IsAny<ILogger>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ThrowsAsync(new InvalidOperationException("Function Add threw an exception"));

//The SUT
var subjectUnderTest = new SettingsStore(iFunctionEnvironment, iblobStorageRepositoryMoq.Object);

//Act
InvalidOperationException exception = await Assert.ThrowsAsync<InvalidOperationException>(() => subjectUnderTest.AddUserSettingsAsync(logger, correlationId, userSettingsObject, userObject));

//Assert
Assert.Equal("Function Add threw an exception", exception.Message);
Assert.Null(exception.InnerException);
}

Note the change to the setup and also if asserting that InvalidOperationException was thrown then mock should actually throw an InvalidOperationException

//...

var iblobStorageRepositoryMoq = new Mock<IBlobStorageRepository>();
iblobStorageRepositoryMoq
.Setup(mock => mock.Add(It.IsAny<ILogger>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ThrowsAsync(new InvalidOperationException("Function Add threw an exception"));

//...

Correct method for testing for an exception using Moq and MSTest

You are right - the second test "SaveCart" works because it's throwing an exception and the the first test fail because you are turning 0. From your response to previous answers, I am sure you already know all of this. If you are asking for the behavior how it failed your first test... it goes like this:

  1. SaveCart is called
  2. It returns an exception (result of your moq setup)
  3. Your try catch caught the exception (you did this on purpose to alter the result)
  4. Your try catch returns 0 (result is now 0 as you intended to alter it)
  5. Assert checks your result against _cartSaveExceptionValue
  6. You get a fail test stating something similar to this "Message: Assert.AreEqual failed. Expected. Actual<0 (System.Int32)>."

If you want to double check this... you can try the following test

  1. comment out the [ExpectedException(typeof())]
  2. change the Assert.AreEqual(result, _cartSaveExceptionValue) to Assert.AreEqual(result, 0);
  3. the test should pass because you are comparing "result" (aka 0) to 0

I hope this answer your question.

How can I throw Exception for async function using Moq

Considering the asynchronous nature of the code under test, it would be better if the test code be asynchronous as well. Moq is async capable

[Fact]
public async Task CreateCSVFile_Failure() {
//Arrange
var dtData = new DataTable();
string fileName = "";
var mockClient = new Mock<IHttpHandler>();

this._iADLS_Operations = new ADLS_Operations(mockClient.Object);

mockClient
.Setup(repo => repo.PostAsync(It.IsAny<string>(), It.IsAny<HttpContent>(), It.IsAny<string>()))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.BadRequest));

mockClient
.Setup(repo => repo.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<string>()))
.ThrowsAsync(new Exception("Some message here"));

//Act
Func<Task> act = () => this._iADLS_Operations.CreateCSVFile(dtData, fileName);

//Assert
Exception ex = await Assert.ThrowsAsync<Exception>(act);
Assert.Contains("Exception occurred while executing method:", ex.Message);
}

Note the use of Moq's ReturnsAsync and ThrowsAsync in the setup, along with xUnit's Assert.ThrowsAsync

This now allows you to avoid making blocking calls like .Result which could potentially lead to deadlocks.

Moq throwing NullReferenceException on Verify with It.Is but not It.IsAny

money.Amount == 0

If money is null, it won't be able to evaluate this and I'd expect a null reference exception.

Changing it to handle the null case should sort it out if that's your issue

It.Is<MoneyWorks.Money>(money => money != null && money.Amount == 0)


Related Topics



Leave a reply



Submit