Azure Storage is still hard to unit test / mock
See original GitHub issueHi Azure Storage team!
(question editted with extra info, about 10 mins after posting this).
This question is a continuation of #349, #318 and sorta #80
With release version 8.*
of the Azure SDK more methods have been virtualized
. Yay! better unit testing 😃
But … I’m not having much luck with some stuff still -> mainly when I need to access a property … which relys on some internal magic … like the Name
of a CloudFile
or CloudDirectory
, etc. This is because the constructors
require specific arguments passed in (I believe).
I think we might need some more things virtualized
=> I think sss
needs to be virtualized.
So … given the latest 8.*
version of the SDK, how could this simple piece of code be Unit Tested?
Here is the code I wish to test: Given a Share
in my Azure File Storage, list all the folders that exist in that share.
Here’s my code which I believe does this…
public class AzureFileServiceExample
{
private readonly CloudFileClient _cloudFileClient;
public AzureFileServiceExample(CloudFileClient cloudFileClient)
{
_cloudFileClient = cloudFileClient;
}
public string[] GetDirectories()
{
// 1. Get a reference to the main, root share directory in yout azure storage account.
var shareRootDirectory = _cloudFileClient.GetShareReference("ShareDirectoryInAzure")
.GetRootDirectoryReference();
// 2. Get a list of all the directories in this share.
var directories = shareRootDirectory.ListFilesAndDirectories()
.OfType<CloudFileDirectory>()
.Select(x => x.Name)
.ToArray();
return directories;
}
}
Here’s a start of some unit testing code to help kick start things to make your life easier :
[Fact]
public void GivenSomeFilesExist_GetDirectories_ReturnsSomeDirectoryNames()
{
// Arrange.
const string uri = "https://pewpew.file.core.windows.net/";
var fakeStorageUri = new StorageUri(new Uri($"{uri}movies/"));
var fakeStorageCredentials = new StorageCredentials();
var existingFilesAndDirectories = new IListFileItem[]
{
new CloudFileDirectory(new StorageUri(new Uri($"{uri}movies/folder-a/")), fakeStorageCredentials),
new CloudFileDirectory(new StorageUri(new Uri($"{uri}movies/folder-b/")), fakeStorageCredentials),
new CloudFile(new StorageUri(new Uri($"{uri}movies/folder-a/file-a.xml")), fakeStorageCredentials),
new CloudFile(new StorageUri(new Uri($"{uri}movies/folder-a/file-b.json")), fakeStorageCredentials),
new CloudFile(new StorageUri(new Uri($"{uri}movies/folder-a/file-c.zip")), fakeStorageCredentials),
new CloudFile(new StorageUri(new Uri($"{uri}movies/folder-b/file-1.xml")), fakeStorageCredentials),
new CloudFile(new StorageUri(new Uri($"{uri}movies/folder-b/file-2.json")), fakeStorageCredentials)
};
var cloudFileDirectory = new Mock<CloudFileDirectory>(fakeStorageUri, fakeStorageCredentials);
cloudFileDirectory.Setup(x => x.ListFilesAndDirectories(null, null))
.Returns(existingFilesAndDirectories);
var cloudFileShare = new Mock<CloudFileShare>(fakeStorageUri, fakeStorageCredentials);
// cloudFileShare.Setup(x => x.GetRootDirectoryReference())
// .Returns(cloudFileDirectory.Object); // <-- Cannot work cause it's not virtual.
var cloudFileClient = new Mock<CloudFileClient>(fakeStorageUri, fakeStorageCredentials);
cloudFileClient.Setup(x => x.GetShareReference(UniqueKeys.AzureFileShareDirectoryKey))
.Returns(cloudFileShare.Object);
var fileService = new AzureFileServiceExample(cloudFileClient.Object);
// Act.
var files = fileService.GetDirectories();
// Assert.
// lots of checks and verifies here.
}
Problem: Because we cannot mock the GetRootDirectoryReference()
method, a real CloudFileDirectory
instance is returned. Which means it will do real hits to the storage endpoints. Not kewl 😢
So - could we please add virtual
to GetRootDirectoryReference()
please?
Side Point: would also love the properties also made virtual also 👍 Like Name
etc…
NOTE: I know this feels like a StackOverflow question, but I wanted to ask here because I’m really asking if the SDK has been designed enough to handle unit testing. Also, please do not suggest using the emulator in a unit testing (manual/local, CI/CD scenario’s) situation please.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:7
- Comments:20 (6 by maintainers)
Top GitHub Comments
I disagree with this one. There is a good reason for using
sealed
on something: you can make sure that no class derives from it. All my classes are eitherabstract
orsealed
. Still, my codebase is perfectly testable.However, as a general rule you need to make sure that the SOLID Principles are kept:
Classes like
CloudStorageAccount
are therefore a horrible construction, since it is a class that represents state and behavior, and also has no interfaces for mocking.