I tried in vain to mock a top-level (not part of any section) configuration value (.NET Core's IConfiguration). For example, neither of these will work (using NSubstitute, but it would be the same with Moq or any mock package I believe):
var config = Substitute.For<IConfiguration>();
config.GetValue<string>(Arg.Any<string>()).Returns("TopLevelValue");
config.GetValue<string>("TopLevelKey").Should().Be("TopLevelValue"); // nope
// non generic overload
config.GetValue(typeof(string), Arg.Any<string>()).Returns("TopLevelValue");
config.GetValue(typeof(string), "TopLevelKey").Should().Be("TopLevelValue"); // nope
In my case, I also need to call GetSection from this same config instance.
You can use an actual Configuration instance with in-memory data.
//Arrange
var inMemorySettings = new Dictionary<string, string> {
{"TopLevelKey", "TopLevelValue"},
{"SectionName:SomeKey", "SectionValue"},
//...populate as needed for the test
};
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(inMemorySettings)
.Build();
//...
Now it is a matter of using the configuration as desired to exercise the test
//...
string value = configuration.GetValue<string>("TopLevelKey");
string sectionValue = configuration.GetSection("SectionName").GetValue<string>("SomeKey");
//...
Reference: Memory Configuration Provider
I do not have idea about NSubstitute, but this is how we can do in Moq.
Aproach is same in either cases.
GetValue<T>() internally makes use of GetSection().
You can Mock GetSection and return your Own IConfigurationSection.
This includes two steps.
1). Create a mock for IConfigurationSection (mockSection) & Setup .Value Property to return your desired config value.
2). Mock .GetSection on Mock< IConfiguration >, and return the above mockSection.Object
Mock<IConfigurationSection> mockSection = new Mock<IConfigurationSection>();
mockSection.Setup(x=>x.Value).Returns("ConfigValue");
Mock<IConfiguration> mockConfig = new Mock<IConfiguration>();
mockConfig.Setup(x=>x.GetSection(It.Is<string>(k=>k=="ConfigKey"))).Returns(mockSection.Object);
Mock IConfiguration
Mock<IConfiguration> config = new Mock<IConfiguration>();
SetupGet
config.SetupGet(x => x[It.Is<string>(s => s == "DeviceTelemetryContainer")]).Returns("testConatiner");
config.SetupGet(x => x[It.Is<string>(s => s == "ValidPowerStatus")]).Returns("On");
IConfiguration.GetSection<T> must be mocked indirectly. I don't fully understand why because NSubstitute, if I understand correctly, creates its own implementation of an interface you're mocking on the fly (in memory assembly). But this seems to be the only way it can be done. Including a top-level section along with a regular section.
var config = Substitute.For<IConfiguration>();
var configSection = Substitute.For<IConfigurationSection>();
var configSubSection = Substitute.For<IConfigurationSection>();
configSubSection.Key.Returns("SubsectionKey");
configSubSection.Value.Returns("SubsectionValue");
configSection.GetSection(Arg.Is("SubsectionKey")).Returns(configSubSection);
config.GetSection(Arg.Is("TopLevelSectionName")).Returns(configSection);
var topLevelSection = Substitute.For<IConfigurationSection>();
topLevelSection.Value.Returns("TopLevelValue");
topLevelSection.Key.Returns("TopLevelKey");
config.GetSection(Arg.Is<string>(key => key != "TopLevelSectionName")).Returns(topLevelSection);
// GetValue mocked indirectly.
config.GetValue<string>("TopLevelKey").Should().Be("TopLevelValue");
config.GetSection("TopLevelSectionName").GetSection("SubsectionKey").Value.Should().Be("SubsectionValue");
I could imagine in some rare scenarios it is needed but, in my humble opinion, most of the time, mocking IConfiguration highlight a code design flaw.
You should rely as much as possible to the option pattern to provide a strongly typed access to a part of your configuration. Also it will ease testing and make your code fail during startup if your application is misconfigured (instead than at runtime when the code reading IConfiguration is executed).
If you really(really) need to mock it then I would advice to not mock it but fake it with an in-memory configuration as explained in #Nkosi's answer
While Nkosi's answer works great for simple structures, sometimes you want to be able to have more complex objects (like arrays) without repeating the whole section path and to be able to use the expected types themselves. If you don't really care too much about performance (and should you in your unit tests?) then this extension method might be helpful.
public static void AddObject(this IConfigurationBuilder cb, object model) {
cb.AddJsonStream(new MemoryStream(Encoding.UTF8.GetString(JsonConvert.SerializeObject(model))));
}
And then use it like this
IConfiguration configuration = new ConfigurationBuilder()
.AddObject(new {
SectionName = myObject
})
.Build();
Use SetupGet method to mock the Configuration value and return any string.
var configuration = new Mock<IConfiguration>();
configuration.SetupGet(x => x[It.IsAny<string>()]).Returns("the string you want to return");
We need to mock IConfiguration.GetSection wichs is executed within GetValue extension method.
You inject the IConfiguration:
private readonly Mock<IConfiguration> _configuration;
and the in the //Arrange Section:
_configuration.Setup(c => c.GetSection(It.IsAny())).Returns(new Mock().Object);
It worked like a charm for me.
I've found this solution to work reliably for me for my XUnit C# tests & corresponding C# code:
In Controller
string authConnection = this._config["Keys:AuthApi"] + "/somePathHere/Tokens/jwt";
In XUnit Test
Mock<IConfiguration> mockConfig = new Mock<IConfiguration>();
mockConfig.SetupGet(x => x[It.Is<string>(s => s == "Keys:AuthApi")]).Returns("some path here");
Related
How do I unit test EntityFrameworkCore.IEntityTypeConfiguration?
I want to make sure that my configuration is unit tested for several reasons:
avoid the burden of creating integration tests which depend more on the data setup
using a feature flag framework, I want to make sure that I map to different views and tables depending on the status of the flag
I was several custom converters which I must make sure are used
simply I want clear self contained tests to fail in case someone changes something that shouldn't, at that point they must intentionally remove a test
I was unable to find an answer to this question, so I had to dig it out myself.
var sut = new MyEntityTypeConfiguration();
var entityType = new EntityType("MyEntityName", typeof(MyEntityName), new Model(), false, ConfigurationSource.Convention);
var builder = new EntityTypeBuilder<MyEntityName>(entityType);
sut.Configure(builder);
// Metadata will contain all the set configurations
var meta = builder.Metadata;
var properties = builder.Metadata.GetDeclaredProperties();
var viewName = builder.Metadata.GetViewName();
[..]
I would recommend to use a method like this in your testing libraries to simplify the setup
private static EntityTypeBuilder<T> GetEntityBuilder<T>() where T : class
{
#pragma warning disable EF1001 // Internal EF Core API usage.
var entityType = new EntityType(typeof(T).Name, typeof(T), new Model(), false, ConfigurationSource.Convention);
var builder = new EntityTypeBuilder<T>(entityType);
return builder;
#pragma warning restore EF1001 // Internal EF Core API usage.
}
which you would use in this way:
var sut = new MyEntityTypeConfiguration();
var builder = GetEntityBuilder<MyEntity>();
sut.Configure(builder);
var meta = builder.Metadata;
var properties = builder.Metadata.GetDeclaredProperties();
var viewName = builder.Metadata.GetViewName();
Once the configure method is called, the builder Metadata property will contain all the details necessary for the correct EF configuration which are accessible and on which you can perform any desired assertion.
I am trying to write a test to verify that X providers are loaded in a certain scenario.
I can resolve the IConfiguration object, how can I tell how many IConfigurationProviders are in it?
In my startup, I use totally bog standard Configuration in my Program
IConfiguration configuration = null;
var builder = Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
{
configuration = hostContext.Configuration;
var startup = new Startup(hostContext.Configuration, hostContext.HostingEnvironment);
//startup.ConfigureServices(services);
})
.ConfigureAppConfiguration((hostContext, config) =>
{
config.AddAzureKeyVaultsFromConfig();
});
builder.Build();
return configuration;
When I'm debugging, I can see my list of Providers when I hover over configuration.
What I would want to do is see that there are 4 providers. I would also want to check and see what type the providers are.
If I use Enumerate() it just gives me a flattened list of all of the values and discards which provider it came from.
The object you have here is actually an IConfigurationRoot, and that happens to also implement IConfiguration. So if you treat it as such, you can access the Providers property. For example:
IConfigurationRoot configuration = null;
// snip the rest of your code
var providerCount = configuration.Providers.Count();
Please checkout the below codes
using Microsoft.Extensions.DependencyInjection;
IServiceProviderFactory<IServiceCollection> serviceProviderFactory =
new DefaultServiceProviderFactory(new ServiceProviderOptions {
ValidateOnBuild = true,
ValidateScopes = true
});
IServiceCollection oldServiceCollection = new ServiceCollection();
IServiceCollection newServiceCollection =
serviceProviderFactory.CreateBuilder(oldServiceCollection);
Assert.IsTrue(oldServiceCollection == newServiceCollection);
I wanted to create a newServiceCollection base on the oldServiceCollection (then modify the newServiceCollection). However (big surprise) the ServiceProviderFactory, despite being a "Factory" with "Create.." methods, it did not create anything...
The newServiceCollection IS the oldServiceCollection. (If I modified the newServiceCollection then the oldServiceCollection will be modified as well).
I think that "DefaultServiceProviderFactory" (of Microsoft) is at fault here, do anybody know a better implementation which can help me clone the oldServiceCollection to make a newServiceCollection?
This is by design. The DefaultServiceProviderFactory isn't useful and only exists for other DI Containers to intercept the creation of IServiceCollection instances.
To make a copy, you'll have to iterate the old collection and add all ServiceDescriptors to the new one:
var newServiceCollection = new ServiceCollection();
foreach (var descriptor in oldServiceCollection)
{
newServiceCollection.Add(descriptor);
}
I'm using SolrNet with Autofac DI in my web application like this:
var solrNetModule = new SolrNetModule(ConfigurationManager.ConnectionStrings["solr"].ConnectionString);
solrNetModule.HttpWebRequestFactory = new BasicAuthHttpWebRequestFactory("****", "****");
builder.RegisterModule(solrNetModule);
My queries are quite long and sometimes end up with a 404 in Jetty, I'm pretty sure this happens because the length of the URL.
I've been reading about the SolrPostConnection and that sounds like a proper solution to my problem, but I'm having trouble implementing it in my Autofac setup.
I know the Autofac SolrNetModule integration internally uses
builder.RegisterInstance(solrConnectionInstance).As<ISolrConnection>();
But I can't figure out how to override it or .Register Autofac to use the SolrPostConnection instead.
Looks like you need to override registration for interface ISolrConnection. The main problem is that SolrNetModule doesn't provide mapping of SolrConnection to itself. Try out the example below. I added another registration of SolrConnection to make it available for injecting to contructor of PostSolrConnection without dependency loops
[Test]
public void SolrRegistrationOverride()
{
// Arrange
var builder = new ContainerBuilder();
var serverUrl = ConfigurationManager.ConnectionStrings["solr"].ConnectionString;
var httpWebRequestFactory = new BasicAuthHttpWebRequestFactory("****", "****");
var solrNetModule = new SolrNetModule(serverUrl);
solrNetModule.HttpWebRequestFactory = httpWebRequestFactory;
builder.RegisterModule(solrNetModule);
builder.RegisterType<SolrConnection>().AsSelf()
.WithParameter(new NamedParameter("serverURL", serverUrl))
.WithProperty("HttpWebRequestFactory", httpWebRequestFactory).AsSelf()
.SingleInstance();
builder.RegisterType<PostSolrConnection>().As<ISolrConnection>()
.WithParameters(new Parameter[]
{
new ResolvedParameter((prm, сtx) => prm.Name == "conn", (prm, ctx) => ctx.Resolve<SolrConnection>()),
new NamedParameter("serverUrl", serverUrl)
});
var container = builder.Build();
// Act
var conn = container.Resolve<ISolrConnection>();
// Assert
Assert.IsInstanceOf<PostSolrConnection>(conn);
}
Hope it helps.
I have found what I think may be a bug in Autofac, but I wanted to see if anybody had a possible solution or workaround so I can make this work.
Basically I have set up a generic decorator, which works fine. The problem is that as soon as I call BeginLifetimeScope() with a configuration delegate, it erroneously resolves multiple components of the same type. If I don't use a configuration delegate with BeginLifetimeScope(), then it works correctly. Unfortunately, I need to add additional dependencies to my child scope, so not using a configuration delegate is not an option.
Here is an example that demostrates the problem:
var builder = new ContainerBuilder();
builder.RegisterType<Dependency>()
.Named<IDependency<object>>("service");
builder.RegisterGenericDecorator(
typeof(Decorator<>), typeof(IDependency<>), "service", "decorated");
var container = builder.Build();
// Returns 1
var scope1 = container.BeginLifetimeScope();
Console.WriteLine(
scope1.ResolveNamed<IEnumerable<IDependency<object>>>("decorated").Count());
// Returns 2 - notice the configAction doesn't even have to do anything
var scope2 = container.BeginLifetimeScope(r => { });
Console.WriteLine(
scope2.ResolveNamed<IEnumerable<IDependency<object>>>("decorated").Count());
And here are my fake types:
interface IDependency<T> { }
class Dependency : IDependency<object> { }
class Decorator<T> : IDependency<T> {}
Any help would be greatly appreciated!
It does just seem like a bug. As a workaround, I ended up doing the following:
var param = new TypedParameter(typeof(IDecoratorDependency), new DecoratorDependency());
var decorated = scope.ResolveNamed<IEnumerable<IDependency<object>>>("decorated", param);
That was good enough for my use case. However, this method is inflexible because it only allows me to supply parameters to the root object, in this case Decorator<T>, but not any of its dependencies.