0

I am new to unit/integration testing, and to the .NET world.

Problem-1 : In one of the integration tests, I have to pass a (mock of) IConfiguration variable, which I currently build as

var mockConfig = GetConfiguration();

    private static IConfiguration GetConfiguration() =>
        new ConfigurationBuilder()
            .SetBasePath($"{Directory.GetCurrentDirectory()})
            .AddJsonFile("appSettings.json", true)
            .AddCommonVariables()
            .Build();

Trial-1: I have tried to do this

    private static Mock<IConfiguration> GetConfiguration() =>
        new Mock<IConfiguration>(new ConfigurationBuilder()
            .SetBasePath($"{Directory.GetCurrentDirectory()})
            .AddJsonFile("appSettings.json", true)
            .AddCommonVariables()
            .Build());

but, it exceptioned out with

Constructor arguments cannot be passed for interface mocks.

Trial-2: I tried to create with the Setup options of Moq

    private static Mock<IConfiguration> GetMockConfiguration()
    {
        var _mockConfigurationBuilder = new Mock<ConfigurationBuilder>();

        //How to setup these methods?
        _mockConfigurationBuilder.Setup(x => x.SetBasePath(It.IsAny<String>())).Returns();
        -_mockConfigurationBuilder.Setup(x => x.AddJsonFile()).Returns()
    }

but I am not sure how to set up these methods.

Problem-2: Is to ultimately mock IDocumentClient, which I use to query my entities

_cosmosWrapper = new CosmosWrapper(mockLogger.Object, mockConfig.Object); use it as

private readonly IDocumentClient _documentClient;
public CosmosWrapper(ILogger<CosmosWrapper> logger, IConfiguration config)
{
  var cosmosConnectionSecretKey = config["cosmosSecretName"];
  var cosmosConnectionString = config[cosmosConnectionSecretKey];
  var cosmosInfo = ConnectionStringParser.Parse(cosmosConnectionString);
  _documentClient = new DocumentClient(new Uri(cosmosInfo["AccountEndpoint"]), cosmosInfo["AccountKey"]);
}

Update:

I had to refactor the setup of document client, by creating a cosmos connection class.

And the setup for mock - cosmos connection was,

    var cosmosConnection = new Mock<ICosmosConnection>();

    cosmosConnection.Setup(c => c.CosmosInfo)
        .Returns(new Dictionary<string, string>(new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("AccountEndpoint", "//string1.string2")
        }));

And finally for mocking the document client, I took ideas from How to (should I) mock DocumentClient for DocumentDb unit testing?

and implemented few more helper methods, for my needs.

private static void SetupProvider(Mock<IFakeDocumentQuery<MyClass>> mockDocumentQuery,
    Mock<IQueryProvider> provider)
{
    provider.Setup(p => p.CreateQuery<MyClass>(It.IsAny<Expression>())).Returns(mockDocumentQuery.Object);
    mockDocumentQuery.As<IQueryable<MyClass>>().Setup(x => x.Provider).Returns(provider.Object);
}

and

private static void SetupMockForGettingEntities(Mock<IDocumentClient> mockDocumentClient,
    IMock<IFakeDocumentQuery<MyClass>> mockDocumentQuery)
{
    mockDocumentClient.Setup(c => c.CreateDocumentQuery<MyClass>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
        .Returns(mockDocumentQuery.Object);
}
Chaipau
  • 129
  • 1
  • 3
  • 11
  • Can you show what the `CosmosWrapper` class is doing with `IConfiguration`? How is it using it and what behavior needs to be mocked? – Nate Barbettini Jul 07 '20 at 04:14
  • @NateBarbettini I have edited my question to reflect my ask. – Chaipau Jul 07 '20 at 04:36
  • 1
    Does this answer your question? [Populate IConfiguration for unit tests](https://stackoverflow.com/questions/55497800/populate-iconfiguration-for-unit-tests) – Pavel Anikhouski Jul 07 '20 at 06:59
  • @PavelAnikhouski Digging through it, I found https://stackoverflow.com/questions/43618686/how-to-setup-mock-of-iconfigurationroot-to-return-value, which I guess implies I shouldn't mock the ConfiguraionBuilder across my directories [base, integration, unit tests etc] but directly use it. – Chaipau Jul 07 '20 at 17:33

1 Answers1

1

Under Trial-1, as the error indicates you should not pass any constructor arguments, e.g. do

private static Mock<IConfiguration> GetConfiguration() {
    var mock = new Mock<IConfiguration>();
    mock.SetupGet(p => p[It.IsAny<string>()]).Returns(string.Empty);
    // or if you want to return specific values:
    mock.SetupGet(p => p[cosmosConnectionSecretKey]).Returns("foo");
    return mock;
}

Edit: see the comment from @Pavel Anikhouski for a potentially cleaner way to accomplish your goals that doesn't require the use of Moq.

Chris Yungmann
  • 925
  • 4
  • 13
  • 1
    @Chaipau I am not sure how `IConfigurationBuilder` factors into this, but I updated my answer to illustrate how to mock the indexer getters. – Chris Yungmann Jul 07 '20 at 05:08