question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Azure Storage is still hard to unit test / mock

See original GitHub issue

Hi 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:closed
  • Created 6 years ago
  • Reactions:7
  • Comments:20 (6 by maintainers)

github_iconTop GitHub Comments

19reactions
PureKromecommented, Jun 8, 2017

16reactions
MovGP0commented, Dec 22, 2017

There should be a requirement to put a comment explaining why is something sealed

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 either abstract or sealed. Still, my codebase is perfectly testable.

However, as a general rule you need to make sure that the SOLID Principles are kept:

  • all classes should either contain state (Entities), or represent behavior (functions), but never both.
  • all classes with behavior need to have an interface to allow mocking (entities may not have interfaces)
    • the base interface might combine multiple interfaces as needed

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to mock or unit test AzureStorageAccount with xunit
Hi, Want to unit test below code: CloudStorageAccount storageAccount = CloudStorageAccount.Parse("connString"); CloudBlobClient blobClient ...
Read more >
c# - CloudTableClient Unit Testing
I found this GitHub issue, Azure Storage is still hard to unit test / mock, but I didn't find any clues in it...
Read more >
Getting started with testing for Azure Blob Storage
Problem with this approach is that we are not able to mock BlobContainerClient object. So, we are not able to write unit tests...
Read more >
How to make mocked unit test for Azure Storage
In this article, we learned to how to mock unit test Azure Blob Storage methods. If you really need to make integration test...
Read more >
How To Simplify C# Unit Testing With a Mocking Framework
The quickest way to take your unit testing to the next level is with a mocking framework. Let's see how they work together....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found