Mock Azure File Share CreateAsync method in unit test - c#

I have the following method, that I'm trying to write some unit tests
public async Task<ShareClient> CreateFileShare(string shareName)
{
if (!ShareNameValidator.IsValid(shareName))
{
throw new ArgumentException("Invalid share name.");
}
ShareClient shareFileClient = _shareServiceClient.GetShareClient(shareName.ToLowerInvariant());
if (await shareFileClient.ExistsAsync())
{
throw new ShareExistsException("Share already exists.");
}
await shareFileClient.CreateAsync();
return shareFileClient;
}
this is part of a helper class, and all the dependencies you're seeing will be available in run-time.
I have 3 nit tests for this. just putting signature, but it's quite straight forward
public async Task CreateFileShare_ShouldThrowException_WhenShareAlreadyExists()
public async Task CreateFileShare_ShouldThrowException_WhenInvalidShareName()
public async Task CreateFileShare_ShouldCreateShare_WhenShareDoesNotExist()
these are xunit tests. first 2 are passing but last one is not. here is the code for last
[Fact]
public async Task CreateFileShare_ShouldCreateShare_WhenShareDoesNotExist()
{
// Arrange
var responseMock = new Mock<Response<bool>>();
string validShareName = "valid-share-name";
responseMock.Setup(x => x.Value).Returns(false);
_shareClientMock.Setup(x => x.ExistsAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(responseMock.Object));
_shareServiceClientMock.Setup(x => x.GetShareClient(validShareName)).Returns(_shareClientMock.Object);
// Act
var createdShareClient = await _fileStorageHelper.CreateFileShare(validShareName);
// Assert
createdShareClient.Should().Be(_shareClientMock.Object);
_shareClientMock.Verify(x => x.CreateAsync(It.IsAny<ShareCreateOptions>(), It.IsAny<CancellationToken>()), Times.Once);
}
the error message:
Message: 
Moq.MockException :
Expected invocation on the mock once, but was 0 times: x =>
x.CreateAsync(It.IsAny<ShareCreateOptions>(),
It.IsAny<CancellationToken>())
Performed invocations:
Mock<ShareClient:1> (x):
ShareClient.ExistsAsync(CancellationToken) => Mock<Response<bool>:1>
ShareClient.CreateAsync(null, null, CancellationToken)
Mock<Response<bool>:1>:
Response<bool>.Value
do you see any wrong set up in my mock?
here is another way I tried:
[Fact]
public async Task CreateFileShare_ShouldCreateShare_WhenShareDoesNotExist()
{
// Arrange
string validShareName = "validsharename";
var responseMock = new Mock<Response<bool>>();
var shareInfoMock = new Mock<ShareInfo>();
var createResponseMock = new Mock<Response<ShareInfo>>();
ShareCreateOptions createOptions = new ShareCreateOptions
{
QuotaInGB = 100,
};
shareInfoMock.DefaultValue = DefaultValue.Mock;
responseMock.Setup(x => x.Value).Returns(false);
createResponseMock.Setup(x => x.Value).Returns(shareInfoMock.Object);
_shareClientMock.Setup(x => x.ExistsAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(responseMock.Object));
_shareClientMock.Setup(x => x.CreateAsync(createOptions, It.IsAny<CancellationToken>())).Returns(Task.FromResult(createResponseMock.Object));
_shareServiceClientMock.Setup(x => x.GetShareClient(validShareName)).Returns(_shareClientMock.Object);
// Act
var createdShareClient = await _fileStorageHelper.CreateFileShare(validShareName);
// Assert
createdShareClient.Should().Be(_shareClientMock.Object);
_shareClientMock.Verify(x => x.ExistsAsync(It.IsAny<CancellationToken>()), Times.Once());
_shareClientMock.Verify(x => x.CreateAsync(It.IsAny<ShareCreateOptions>(), It.IsAny<CancellationToken>()), Times.Once());
}
failing with the same error.

the problem is in verify part
instead of
_shareClientMock.Verify(x => x.CreateAsync(It.IsAny<ShareCreateOptions>(), It.IsAny<CancellationToken>()), Times.Once());
have this
_shareClientMock.Verify(x => x.CreateAsync(It.IsAny<Dictionary<string, string>>(), null, It.IsAny<CancellationToken>()), Times.Once());
the reason for this,as it is saying in the error message is that it calls another overloaded version of CreateAsync method.
credit to Nick :)

Related

Redis StringSetAsync returns false in Unit Tests using Moq

I am currently writing unit tests for a RedisProvider Class for my Solution. I have a method in my class that sets a key in the Redis Cache:
public async Task<bool> StringSetAsync(string key, string value)
{
var cache = multiplexer.GetDatabase();
//Some other stuff
result = await cache.StringSetAsync(key, value);
return result;
}
In my unit tests I have the following setup:
var mockMultiplexer = new Mock<IConnectionMultiplexer>();
mockMultiplexer.Setup(_ => _.IsConnected).Returns(true);
mockMultiplexer.Setup(_ => _.Configuration).Returns(MockedData.CacheConnectionString);
var mockDatabase = new Mock<IDatabase>();
mockMultiplexer
.Setup(_ => _.GetDatabase(It.IsAny<int>(), It.IsAny<object>()))
.Returns(() => mockDatabase.Object);
RedisCacheProvider mockedCacheProvider = new RedisCacheProvider(new Mock<ILogger<RedisCacheProvider>>
().Object, mockMultiplexer.Object);
var result = await mockedCacheProvider.StringSetAsync(It.IsAny<string>(), It.IsAny<string>());
When I run the above code for my unit test, the result that I receive is always false. Is there a way to get a true result? What is wrong over here?
I realized that this should be mocked by the services using the class rather than validating this on the class itself.
Here you go:
mockedCacheProvider.Setup(h => h.StringSetAsync(
It.IsAny<string>(),
It.IsAny<string>())).ReturnsAsync(() => true);

How can I throw Exception for async function using Moq

I am writing test cases using xUnit and Moq.
I am using below code in Test class for testing catch() of another class method
private readonly IADLS_Operations _iADLS_Operations;
[Fact]
public void CreateCSVFile_Failure()
{
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>()))
.Returns(() => Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest)));
mockClient.Setup(repo => repo.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<string>()))
.Returns(() => Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest))); // here I want to return Exception instead of BadRequest. How to do that.
Exception ex = Assert.Throws<Exception>(() => this._iADLS_Operations.CreateCSVFile(dtData, fileName).Result);
Assert.Contains("Exception occurred while executing method:", ex.Message);
}
In below code, I want to return Exception instead of BadRequest.
mockClient.Setup(repo => repo.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<string>()))
.Returns(() => Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest)));
How to achieve that.
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.
As #Johnny mentioned in the comments, you can replace the Returns in your code with Throws like:
mockClient.Setup(repo => repo.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<string>()))
.Throws(new Exception("exception message"));
In addition, you could also throw an exception like:
mockClient.Setup(repo => repo.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<string>()))
.Throws<InvalidOperationException>();
You can find more information about throwing exceptions and moq here.

Mocking async query operations

I created unit test and I have to mock context of my EF. I use Moq library and Xunit. I have a test method like this:
[Fact]
public async Task DeleteAttachmentCommandHandler_WithValidCommand_ShouldCallSaveChangesAsyncOnce()
{
var command = new DeleteAttachmentCommand { Id = Guid.NewGuid() };
var attachments = new List<Attachment>();
var dbSetMock = attachments.AsQueryable().BuildMockDbSetForAsyncQueryOperations();
_context.Setup(x => x.Set<Attachment>()).Returns(dbSetMock.Object);
_context.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>())).ReturnsAsync(1).Verifiable();
await Act(command);
_context.Verify(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
}
The _context is of type Mock<IEmployeeSettlementsDbContext>
The BuildMockDbSetForAsyncQueryOperations is my extension method thanks to the MSDN documentation -> https://learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking, which uses the async providers like TestDbAsyncEnumerable, TestDbAsyncEnumerator, TestDbAsyncQueryProvider. And my extension BuildMockDbSetForAsyncQueryOperations looks like this:
public static Mock<IDbSet<TEntity>> BuildMockDbSetForAsyncQueryOperations<TEntity>(this IQueryable<TEntity> data) where TEntity : class
{
var dbSetMock = new Mock<IDbSet<TEntity>>();
dbSetMock.As<IDbAsyncEnumerable<TEntity>>().Setup(x => x.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<TEntity>(data.GetEnumerator()));
dbSetMock.As<IQueryable<TEntity>>().Setup(x => x.Provider).Returns(new TestDbAsyncQueryProvider<TEntity>(data.Provider));
dbSetMock.As<IQueryable<TEntity>>().Setup(x => x.Expression).Returns(data.Expression);
dbSetMock.As<IQueryable<TEntity>>().Setup(x => x.ElementType).Returns(data.ElementType);
dbSetMock.As<IQueryable<TEntity>>().Setup(x => x.GetEnumerator()).Returns(data.GetEnumerator());
return dbSetMock;
}
In my actual handler method which is testing I have a line:
var attachment = await _context.Set<Attachment>()
.SingleAsync(x => x.Id == command.Id);
And when I run the test it fails and show me the message
Message: System.InvalidOperationException : The sequence does not contain a matching element.
But when I change the query in handler to be ListAsync() instead of SingleAsync() then the mock is setup correctly and returns me an empty list. But it does not work for the single element using SingleAsync().
EDIT:
Here is my full Handler method:
public async Task<Unit> Handle(DeleteAttachmentCommand command, CancellationToken cancellationToke = default(CancellationToken))
{
ValidateCommand(command);
var attachment = await _context.Set<Attachment>().SingleAsync(x => x.Id == command.Id);
attachment.IsDeleted = true;
await _context.SaveChangesAsync();
return Unit.Value;
}
SingleAsync() documentation in MSDN
Asynchronously returns the only element of a sequence, and throws an
exception if there is not exactly one element in the sequence.
Consider to use FirstOrDefault()or FirstOrDefaultAsync() method instead of SingleAsync(). Here and here are a link about that, this will not throw exception.

Why can't I setup CancellationToken?

I'm trying to write a test for a class and it seems that I can't setup the CheckLoginAsync method of mine. This CheckLoginAsync method has 2 parameters. The second parameter is an optional one and looks like this:
public async Task CheckLoginAsync(ISettings userSettings, CancellationToken? cancellationToken = null);
The setup code is the following:
backendFacadeMock = new Mock<BackendFacade>(MockBehavior.Strict);
backendFacadeMock
.Setup(bf => bf.Initialize())
.Returns(() => Task.FromResult(0));
backendFacadeMock
.Setup(bf => bf.CheckLoginAsync(It.IsAny<ISettings>(), It.IsAny<CancellationToken?>()))
.Returns(() => Task.FromResult(0));
nullBackendFacadeMock = new Mock<IBackendFacade>(MockBehavior.Strict);
backendFacadeFactoryMock = new Mock<IBackendFacadeFactory>(MockBehavior.Strict);
backendFacadeFactoryMock
.Setup(bf => bf.CreateBackendFacade())
.Returns(() => backendFacadeMock.Object);
backendFacadeFactoryMock
.Setup(bf => bf.CreateNullBackendFacade())
.Returns(() => nullBackendFacadeMock.Object);
The code that is being tested is the following:
private async Task<IBackendFacade> CreateBackendFacade()
{
IBackendFacade backendFacade = _backendFacadeFactory.CreateBackendFacade();
try
{
await backendFacade.CheckLoginAsync(_userSettings);
await backendFacade.Initialize();
}
catch (Exception e)
{
backendFacade = _backendFacadeFactory.CreateNullBackendFacade();
}
return backendFacade;
}
The CheckLoginAsync invocation in the code mentioned above throws the following exception:
IBackendFacade.CheckLoginAsync(Mock<de.cas.officeintegration.outlook.core.application.ISettings:00000001>.Object, null) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
The test itself:
[Test]
public async Task GetBackendFacadeAsync_NoException_ReturnsABackendFacadeObject()
{
var backendFacadeProvider = new BackendFacadeProvider(backendFacadeFactoryMock.Object, userSettingsMock.Object);
IBackendFacade backendFacade = await backendFacadeProvider.GetBackendFacadeAsync();
Assert.AreSame(backendFacadeMock.Object, backendFacade);
}
Thanks in advance!

Moq mocked call returns null if using setup

I am writing tests for a C# application, using Moq. My test initialiser has the following code:
UnityContainer unityContainer = new UnityContainer();
_serviceMock = new Mock<IService>();
_serviceMock.Setup(mock => mock.GetSearchInfoAsync(It.IsAny<CancellationToken>(), It.IsAny<IEnumerable<string>>(), It.IsAny<identifierType>(), It.IsAny<bool>())).Callback(() => _count++);
unityContainer.RegisterInstance(typeof(IService), _serviceMock.Object, new ContainerControlledLifetimeManager());
I want to test that a call is made only once. I am trying it like this:
int _count = 0;
[TestMethod]
public void Properties_Test()
{
_serviceMock.Verify(mock => mock.GetSearchInfoAsync(It.IsAny<CancellationToken>(), It.IsAny<IEnumerable<string>>(), It.IsAny<identifierType>(), It.IsAny<bool>()), Times.Exactly(1), "Invocation was performed " + _count + " times but was expected only once!");
}
This is the method where it actually gets called:
private void Search(string queryValue, identifierType identifierType)
{
CancellationToken cancellationToken;
lock (_syncLock)
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
cancellationToken = _cancellationTokenSource.Token;
}
IService Service = ServiceLocator.Current.GetInstance<IService>();
Service.GetSearchInfoAsync(cancellationToken, new[] {queryValue}, identifierType)
.ContinueWith(
task =>
{
// Do stuff
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
}
The problem is that if I use this line as detailed above,
_serviceMock.Setup(mock => mock.GetSearchInfoAsync(It.IsAny<CancellationToken>(), It.IsAny<IEnumerable<string>>(), It.IsAny<identifierType>(), It.IsAny<bool>())).Callback(() => _count++);
this returns null and generates a NullPointerException:
Service.GetSearchInfoAsync(cancellationToken, new[] {queryValue}, identifierType)
However, if I comment out that line, the tests run fine (albeit not counting the number of calls).
What am I doing wrong? This is my first time using Moq for this and as far as I can tell I've implemented the count functionality correctly.
EDIT: Following Chris Sinclair's suggestion, I've changed the initialiser to this, which fixed the issue:
UnityContainer unityContainer = new UnityContainer();
_serviceMock = new Mock<IService>();
Task<IEnumerable<ISearchResult>> task = new Task<IEnumerable<ISearchResult>>(Enumerable.Empty<ISearchResult>);
_serviceMock.Setup(mock => mock.GetSearchInfoAsync(It.IsAny<CancellationToken>(), It.IsAny<IEnumerable<string>>(), It.IsAny<identifierType>(), It.IsAny<bool>())).Returns(task).Callback(() => _count++);
unityContainer.RegisterInstance(typeof(IService), _serviceMock.Object, new ContainerControlledLifetimeManager());
When you "Setup" the method, you set a callback but you don't provide a return value. As such, when the mocked method is called, it will return the default value for the return type (in this case, a Task<> type will result in a null return value). As such, when your Search method calls your mocked GetSearchInfoAsync method, it receives a null reference which naturally fails when it later attempts to invoke .ContinueWith on it.
Try adding a .Returns() which feeds a dummy Task<> to your mocked method:
_serviceMock.Setup(mock => mock.GetSearchInfoAsync(It.IsAny<CancellationToken>(), It.IsAny<IEnumerable<string>>(), It.IsAny<identifierType>(), It.IsAny<bool>()))
.Returns(new Task<IEnumerable<ISearchResult>>(Enumerable.Empty<ISearchResult>))
.Callback(() => _count++);

Categories

Resources