How to configure Moq via builder - c#

I'm trying out Moq and the builder pattern to set up services for testing CRM plugins. On the builder I have a ConfigureMock<T>(Expression<Action<Mock<T>>>) to inject individual configurations. My problem is that once a service is .Setup(), I would like to get the entity the service worked on via .Callback<Entity>(), but I cannot assign it to a local variable in the test, because I can't do assignments in the callback expression.
Here is the config:
private readonly Dictionary<Type, object> MockServices = new Dictionary<Type, object>();
public PluginContextBuilder ConfigMock<T>(Expression<Action<Mock<T>>> setupConfig) where T : class
{
object svc = null;
if (MockServices.TryGetValue(typeof(T), out svc))
{
var mockSvc = (Mock<T>) svc;
Action<Mock<T>> setup = setupConfig.Compile();
setup(mockSvc);
}
return this;
}
And here's an example how I would like to configure in the test (but will not compile):
var createdFanClub = null;
var context = new PluginContextBuilder()
.ConfigMock<IOrganizationService>(c =>
c.Setup(s =>
s.Create(It.IsAny<Entity>()))
.Returns(fanclubGuid))
.Callback<Entity>(a => createdFanClub = a))
If I create an additional Action<Entity> which does the assignment, it works, but I don't think it's practical, in case I have multiple entities, I will need to make just as many assignments for them:
Entity createdFanClub = null;
Action<Entity> assign = a => createdFanClub = a;
var context = new PluginContextBuilder()
.ConfigMock<IOrganizationService>(c =>
c.Setup(s =>
s.Create(It.IsAny<Entity>()))
.Returns(fanclubGuid))
.Callback<Entity>(assign))

Not sure what you try to accomplish. If the goal is to have a builder, which has a handle to all the mocks needed, then why not just return the mock itself, and configure it as one normally will do:
builder.GetMock<IOrganizationService>().Setup....
That will prevent you to chain calls on the same builder (as I see you are trying to do), but it's not a big trade-off, and will simplify your setups.

Related

How to Substitute IConfigurationSection .Get<ExampleConfig>() [duplicate]

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");

.NET Core how to unit test service?

I have build a WebAPI and want to create a unit test project to have my services tested automatically.
The flow of my WebAPI is simple:
Controller (DI Service) -> Service (DI Repository) -> _repo CRUD
Suppose I have a service like:
public int Cancel(string id) //change status filed to 'n'
{
var item = _repo.Find(id);
item.status = "n";
_repo.Update(item);
return _repo.SaveChanges();
}
And I want to build a unit test, which just use InMemoryDatabase.
public void Cancel_StatusShouldBeN() //Testing Cancel() method of a service
{
_service.Insert(item);
int rs = _service.Cancel(item.Id);
Assert.Equal(1, rs);
item = _service.GetByid(item.Id);
Assert.Equal("n", item.status);
}
I've searched other related question, found that
You can't use dependency injections on test classes.
I just want to know if there is any other solution to achive my unit test idea?
When unit testing, you should just supply all the dependencies of the class you are testing explicitly. That is dependency injection; not having the service construct its dependencies on its own but making it rely on the outer component to provide them. When you are outside of a dependency injection container and inside a unit test where you are manually creating the class you are testing, it’s your responsibility to provide the dependencies.
In practice, this means that you either provide mocks or actual objects to the constructor. For example, you might want to provide a real logger but without a target, a real database context with a connected in-memory database, or some mocked service.
Let’s assume for this example, that the service you are testing looks like this:
public class ExampleService
{
public ExampleService(ILogger<ExampleService> logger,
MyDbContext databaseContext,
UtilityService utilityService)
{
// …
}
// …
}
So in order to test ExampleService, we need to provide those three objects. In this case, we will do the following for each:
ILogger<ExampleService> – we will use a real logger, without any attached target. So any call on the logger will work properly without us having to provide some mock, but we do not need to test the log output, so we do not need a real target
MyDbContext – Here, we’ll use the real database context with an attached in-memory database
UtilityService – For this, we will create a mock which just setups the utility method we need inside the methods we want to test.
So a unit test could look like this:
[Fact]
public async Task TestExampleMethod()
{
var logger = new LoggerFactory().CreateLogger<ExampleService>();
var dbOptionsBuilder = new DbContextOptionsBuilder().UseInMemoryDatabase();
// using Moq as the mocking library
var utilityServiceMock = new Mock<UtilityService>();
utilityServiceMock.Setup(u => u.GetRandomNumber()).Returns(4);
// arrange
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// fix up some data
db.Set<Customer>().Add(new Customer()
{
Id = 2,
Name = "Foo bar"
});
await db.SaveChangesAsync();
}
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// create the service
var service = new ExampleService(logger, db, utilityServiceMock.Object);
// act
var result = service.DoSomethingWithCustomer(2);
// assert
Assert.NotNull(result);
Assert.Equal(2, result.CustomerId);
Assert.Equal("Foo bar", result.CustomerName);
Assert.Equal(4, result.SomeRandomNumber);
}
}
In your specific Cancel case, you want to avoid using any methods of the service you are not currently testing. So if you want to test Cancel, the only method you should call from your service is Cancel. A test could look like this (just guessing the dependencies here):
[Fact]
public async Task Cancel_StatusShouldBeN()
{
var logger = new LoggerFactory().CreateLogger<ExampleService>();
var dbOptionsBuilder = new DbContextOptionsBuilder().UseInMemoryDatabase();
// arrange
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// fix up some data
db.Set<SomeItem>().Add(new SomeItem()
{
Id = 5,
Status = "Not N"
});
await db.SaveChangesAsync();
}
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// create the service
var service = new YourService(logger, db);
// act
var result = service.Cancel(5);
// assert
Assert.Equal(1, result);
}
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
var item = db.Set<SomeItem>().Find(5);
Assert.Equal(5, item.Id);
Assert.Equal("n", item.Status);
}
}
Btw. note that I’m opening up a new database context all the time in order to avoid getting results from the cached entities. By opening a new context, I can verify that the changes actually made it into the database completely.

Unit Testing Codeactivity Workflow

I am trying to write a unit test for a CodeActivity Workflow. My test so far is only
[TestMethod]
public void BusinessUnitTest()
{
WorkflowInvoker invoker = new WorkflowInvoker(new DespatchStockOrder());
invoker.Extensions.Add<ITracingService>(() => tracingService);
invoker.Extensions.Add<IWorkflowContext>(() => workflowContext);
invoker.Extensions.Add<IOrganizationServiceFactory>(() => factory);
IDictionary<string, object> outputs = invoker.Invoke();
}
This works fine and runs the workflow. However I get a null referrence when I hit this line in the workflow.
// Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
if (context == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
}
Entity entity = new Entity(context.PrimaryEntityName) //This line errors with PrimaryEntityName null
{
Id = context.PrimaryEntityId,
LogicalName = context.PrimaryEntityName
};
My question is how do I get context.PrimaryEntityName witha value in a unit test
If you are building the context manually then you will need to populate the PrimaryEntityName in the [TestMethod]. You should probably look further into how your workflowContext test object is constructed.
[TestMethod]
public void BusinessUnitTest()
{
workflowContext.PrimaryEntityName = "Entity name";
WorkflowInvoker invoker = new WorkflowInvoker(new DespatchStockOrder());
invoker.Extensions.Add<ITracingService>(() => tracingService);
invoker.Extensions.Add<IWorkflowContext>(() => workflowContext);
invoker.Extensions.Add<IOrganizationServiceFactory>(() => factory);
IDictionary<string, object> outputs = invoker.Invoke();
}
You might want to try FakeXrmEasy. It's an open source unit testing library I'm maintaining to facilitate unit testing for Dynamics Crm without mocking anything.
You get a reference to a workflow context and inject whatever parameters you need, including Primary Entity names and Id's.
But the most common crm messages are already mocked (retrieve multiple requests, CRUD, fetchxml, LINQ, QueryExpressions, and so no...)

Unit Test Using Moq

I am unit-testing an async method that returns a List<T>. This method has a dependency on a mapping class/interface. In my unit-test, I am mocking the mapping class using moq. The test runs okay, and the returned list has items, but the values of the items is null. I think the problem is because I haven't stubbed-out the mapping classes methods properly. I don't have a lot of experience with testing, so any guidance is appreciated.
Test Method:
[TestMethod]
[TestCategory("CSR.Data.Tests.Services.ServiceSearchTest")]
public void SearchAccount()
{
// Arrange
var mapper = new Mock<CSR.Data.Mapping.Interfaces.IMapper<Account, AccountDTO>>();
mapper.Setup(i => i.Initialize());
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(It.IsAny<Account>);
mapper.Setup(i => i.DomainToDto(It.IsAny<Account>())).Returns(It.IsAny<AccountDTO>);
var service = new ServiceSearch(null,mapper.Object);
string accountNumber = "123";
string accountName = "";
// Act
var results = service.SearchAccount(accountNumber, accountName);
// Assert
Assert.IsTrue(results.Result.Count >= 1);
}
Method/Class That I'm Testing:
public class ServiceSearch : IServiceSearch
{
public ServiceSearch(IMapper<Claim, ClaimDTO> claimMapper, IMapper<Account, AccountDTO> accountMapper)
{
_claimMapper = claimMapper;
_accountMapper = accountMapper;
}
public async Task<List<AccountDTO>> SearchAccount(string accountNumber, string accountName)
{
var accounts = new List<Account>();
var accountDTOs = new List<AccountDTO>();
var results = await Task.Run(() => base.AccountSearch(accountNumber, accountName).Result);
if (results != null && results.Count > 0)
{
//Map DH to Domain
_accountMapper.Initialize();
foreach (AccountSearchResult result in results)
{
accounts.Add(_accountMapper.ToDomain(result));
}
//Map Domain to DTO
foreach (Account account in accounts)
{
accountDTOs.Add(_accountMapper.DomainToDto(account));
}
}
return accountDTOs;
}
}
This isn't the best place to use a Mock object because you are going to spend a lot of time writing your test objects and mock results. The issue with the setup call is that you haven't configured anything to send back in the result. A correct example would be:
// you would fully configure this object
AccountDTO expectedResult = new AccountDTO();
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(expectedResult);
Now you can use the setup to configure different accountDTOs for different inputs.
You call also configure a callback to generate the account at test time:
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns<AccountSearchResult>(sr => {
// build and return your dto here
});
However, unless your mapper is expensive to run or create, I think you'd better off just ensure that it is fully tested and acceptable and then use it to go ahead and generate the DTOs directly instead of trying to mock it out.
You don't actually setup an object in the ".Returns" call. You need to make sure to setup the ".Returns" to actually have an object with values.

NHibernate ClassMap<T> code not executing

I'm setting up a new project and have gotten NHibernate to work with structuremap...sorta. I'm using the NHibernate.Mapping.ByCode.Conformist setup with ClassMaps. No errors occur, but when I query over a session and there are records present in the database for a particular type, nothing comes back. Upon further examination, it appears that the mappings that I've set up for these types are not executing. Here's my code that wires up things for structuremap. I can confirm that it is being executed.
public class OrmRegistry : Registry
{
public OrmRegistry()
{
var sessionFactory = BuildSessionFactory();
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(s => sessionFactory.OpenSession());
}
public ISessionFactory BuildSessionFactory()
{
var cfg = new Configuration().DataBaseIntegration(db =>
{
db.ConnectionStringName = "LocalSqlServer";
db.Dialect<MsSql2008Dialect>();
db.Driver<SqlClientDriver>();
db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
db.IsolationLevel = IsolationLevel.ReadUncommitted;
db.BatchSize = 500;
}).AddAssembly(Assembly.GetExecutingAssembly());
if(HttpContext.Current != null)
{
cfg.CurrentSessionContext<WebSessionContext>();
}
else
{
cfg.CurrentSessionContext<ThreadStaticSessionContext>();
}
return cfg.BuildSessionFactory();
}
}
I'm nearly certain I'm just missing something extremely obvious here, but I've been looking at it for a few hours and haven't had any success. I also got downsized a couple days ago, so I don't have a coworker around to look at it.
Looks like you got your configuration initialized, but what about mapping? You need to initialize mappings like this (if you are using conventions):
var mapper = new ConventionModelMapper();
// TODO: define conventions here using mapper instance
// just an example on how I have been using it
var entities = ... // get all entity types here
cfg.AddDeserializedMapping(mapper.CompileMappingFor(entities), "MyMappings");
return cfg.BuildSessionFactory();
And another example if you are using mapping classes (from this post):
var mapper = new ModelMapper();
var mappingTypes = typeof (InvoiceMapping).Assembly.GetExportedTypes()
.Where(t => t.Name.EndsWith("Mapping")).ToArray();
mapper.AddMappings(mappingTypes);
cfg.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());
return cfg.BuildSessionFactory();

Categories