I'm currently trying to implement StructureMap's AutoMocking functionality and I need help with getting the mocked .
I have a Test method as follows:
[Test]
public void DirctoryResult_Returns_Groups()
{
var autoMocker = new RhinoAutoMocker<GroupController>(MockMode.AAA);
GroupController controller = autoMocker.ClassUnderTest;
var directoryResult = controller.DirectoryResult("b");
var fundDirectoryViewModel = (FundDirectoryViewModel)directoryResult.ViewData.Model;
Assert.IsNotNull(fundDirectoryViewModel.Groups);
}
Currently the test is failing because fundDirectoryViewModel.Groups is null.
The real implementation of DirectoryResult is as follows:
private readonly IGroupService _groupService;
public PartialViewResult DirectoryResult(string query)
{
return PartialView(new FundDirectoryViewModel
{
Groups =_groupService.GetGroupsByQuery(query)
});
}
where _groupService.GetGroupsByQuery(query) uses an interface to IGroupRepository to read data from the database. Of course, I don't want my test to read data from the actual database, but can somebody tell me how to get mock data for it?
What do I need to do to get the AutoMocker to mock the fake data for me?
update:
for reference, this is the definition of GroupService & GroupRepository
public class GroupService : IGroupService
{
private readonly IGroupRepository _groupRepository;
public GroupService(IGroupRepository groupRepository)
{
_groupRepository = groupRepository;
}
public IList<CompanyGroupInfo> GetGroupsByQuery(string query)
{
return _groupRepository.GetGroupsByQuery(query);
}
}
public class GroupRepository : DataUniverseRepository, IGroupRepository
{
public GroupRepository(ISession session)
{
_session = session;
}
public IList<CompanyGroupInfo> GetGroupsByQuery(string query)
{
// dig into the database and return stuff with _session..
}
}
I've been informed that the question was wrong. Automocker doesn't mock data like that. It's up to me to specify the fake data with Rhino Mocks.
This works:
[Test]
public void DirctoryResult_Returns_Groups()
{
var service = autoMocker.Get<IGroupService>();
service.Expect(srv => srv.GetGroupsByQuery(Arg<string>.Is.Anything))
.Return(new List<CompanyGroupInfo>
{
new CompanyGroupInfo(),
new CompanyGroupInfo(),
new CompanyGroupInfo()
});
service.Replay();
var directoryResult = _controller.DirectoryResult("b");
var fundDirectoryViewModel = (FundDirectoryViewModel)directoryResult.ViewData.Model;
Assert.That(fundDirectoryViewModel.Groups.Count, Is.EqualTo(3));
service.AssertWasCalled(srv => srv.GetGroupsByQuery(Arg<string>.Is.Equal("b")));
}
Related
I'm developing an API which communicates with MongoDB and I need to create some statistics from one collection. I have the following service:
public class BoxService : IBoxService
{
private readonly IMongoCollection<Box> _boxCollection;
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
_boxCollection = mongoDatabase.GetCollection<Box>(dbSettings.Value.BoxCollectionName);
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var results = await _boxCollection.AsQueryable()
.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty })
.ToListAsync();
// More calculations with the results list
return boxNumberStatisticsList;
}
}
And the following test:
public class BoxServiceTest
{
private readonly IMongoCollection<Box> _boxCollection;
private readonly List<Box> _boxes;
private readonly IBoxService _boxService;
public BoxServiceTest()
{
_boxCollection = A.Fake<IMongoCollection<Box>>();
_boxes = new List<Box> {...};
var mockOptions = A.Fake<IOptions<DbSettings>>();
var mongoClient = A.Fake<IMongoClient>();
var mongoDb = A.Fake<IMongoDatabase>();
A.CallTo(() => mongoClient.GetDatabase(A<string>._, default)).Returns(mongoDb);
A.CallTo(() => mongoDb.GetCollection<Box>(A<string>._, default)).Returns(_boxCollection);
_boxService = new BoxService(mockOptions, mongoClient);
}
}
This is working so far, the BoxService is created with the fake parameters and I can test other functionalities of the service (FindAll, FindById, Create, etc.) but how can I test the GetBoxNumberStatisticsAsync function? I can't fake the AsQueryable because it's an extension method.
As you've noted, you can't fake an extension method. This question is asked every once in a while. For example, see Faking an Extension Method in a 3rd Party Library. There are a few approaches:
if the static method is simple enough, to divine what it does and fake the non-static methods that it calls
add a layer of indirection: wrap the call to the extension method in an interface that you can fake
don't fake the database. Instead, replace it with some in-memory analogue, if one exists (I don't know what's available for Mongo)
Here is what I ended up with. A base interface for all my services:
public interface IBaseService<T>
{
//generic method definitions for all services: Findall, FindById, Create, Update
}
An abstract class to have a generic constructor:
public abstract class BaseService<T> : IBaseService<T>
{
protected BaseService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient, string collectionName)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
Collection = mongoDatabase.GetCollection<T>(collectionName);
}
protected IMongoCollection<T> Collection { get; }
// abstract method definitions for IBaseService stuff
public virtual async Task<List<T>> CollectionToListAsync()
{
return await Collection.AsQueryable().ToListAsync();
}
}
An interface for my BoxService:
public interface IBoxService : IBaseService<Box>
{
public Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync();
}
The service itself:
public class BoxService : BaseService<Box>, IBoxService
{
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
: base(dbSettings, mongoClient, dbSettings.Value.BoxCollectionName)
{
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var list = await CollectionToListAsync();
var results = list.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty }).ToList();
//...
return boxNumberStatisticsList;
}
}
And finally the test:
public async Task GetBoxNumberStatisticsAsync_ReturnsStatistics()
{
// Arrange
var expected = new List<BoxStatisticsDto> {...};
var fakeService = A.Fake<BoxService>(options => options.CallsBaseMethods());
A.CallTo(() => fakeService.CollectionToListAsync()).Returns(_boxes);
// Act
var boxList = await ((IBoxService)fakeService).GetBoxNumberStatisticsAsync();
// Assert
}
I'm not a huge fan of making the CollectionToListAsync public, but nothing really worked for me here. I tried creating IQueryable and IEnumerable from my list and convert them to IMongoQueryable but no success. I also tried faking the IMongoQueryable but I couldn't execute the Select on it as it gave an error that the 'collectionNamespace' can't be null and the CollectionNamespace can't be faked, because it's a sealed class.
I am trying to write some tests for an existing service we have. It uses the DbContext (In our case, named DatabaseContext) and the constructor looks like this:
public GenericOrderProvider(DatabaseContext context, IOrderHandler<T> orderHandler)
{
_orderHandler = orderHandler;
_context = context;
_dbSet = context.Set<T>();
}
As you can see, it's generic and sets the _dbSet when it's initialized.
I have this very simple method:
public Attempt<IQueryable<T>> List(params string[] includes)
{
var x = _dbSet.ToList();
return Attempt<IQueryable<T>>.Succeed(_dbSet.OrderBy(m => m.Order));
}
And I wrote this test:
[TestFixture]
public class ListShould
{
[Test]
public void ReturnList()
{
// Assemble
var services = GenericOrderProviderContext.GivenServices();
var provider = services.WhenCreateOrderProvider();
services.DatabaseContext.Set<Attribute>().ReturnsForAnyArgs(new List<Attribute>().ToDbSet());
//services.DatabaseContext.Attributes = new List<Attribute>().ToDbSet();
// Act
var result = provider.List();
// Assert
result.Failure.Should().BeFalse();
result.Result.Count().Should().Be(0);
}
}
When I run that test, I get the error:
NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException : Could not find a call to return from.
The trace specifically targets the line services.DatabaseContext.Set<Attribute>().ReturnsForAnyArgs(new List<Attribute>().ToDbSet()); but I have no idea how to fix it.
As far as I can tell, I am mapping to the right method.
For completeness, here is my test Contexts:
public class GenericOrderProviderContext: DatabaseContextContext<GenericOrderProviderContext>
{
public static GenericOrderProviderContext GivenServices() => new GenericOrderProviderContext();
public IGenericOrderProvider<Attribute> WhenCreateOrderProvider() =>
new GenericOrderProvider<Attribute>(DatabaseContext,
new OrderHandler<Attribute>(DatabaseContext));
public bool IsSequential(List<Attribute> models)
{
return !models.OrderBy(m => m.Order).Select(m => m.Order).Select((i, j) => i - j).Distinct().Skip(1).Any();
}
}
public class DatabaseContextContext<T> where T: DatabaseContextContext<T>
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
DatabaseContext = Substitute.For<DatabaseContext>();
}
}
Does anyone know what I can do to resolve this issue?
I created Test for a method that is being tested using MOQ & NUnit. The method to be tested will will another method using an object of that corresponding class. When I try to mock that called method, I am not able to invoke the mocked method. How to mock this method, because my testing method is using the other said method. Please help me on this.
public DataSet ExecuteCondition()
{
var ObjClass1 = new Class1();
....
var result = ObjClass1.VerifyPrecondition(query);
....
}
public class Class1:IClass1
{
public string VerifyPrecondition(string query)
{
....
return text;
}
}
So, I suppose this should look like this:
Class with ExecuteCondition() method:
public class DataClass
{
private readonly IClass1 _class1;
public DataClass(IClass1 class1)
{
_class1 = class1;
}
public DataSet ExecuteCondition()
{
//....
var result = _class1.VerifyPrecondition(query);
//....
}
}
Test:
[Test]
public void Test()
{
var mockClass1 = new Mock<IClass1>();
mockClass1.Setup(x => x.VerifyPrecondition(It.IsAny<string>())).Returns("test");
var dataClass = new DataClass(mockClass1.Object);
dataClass.ExecuteCondition();
//Assert
}
I've a class with several services injected in its constructor. I'm using Autofixture with xUnit.net and NSubstitute, and created an attribute to setup the global customization.
public class AutoDbDataAttribute : AutoDataAttribute
{
public AutoDbDataAttribute() : base(() => new Fixture().Customize(new AutoNSubstituteCustomization()))
{
}
public AutoDbDataAttribute(Type customizationType) : base(() =>
{
var customization = Activator.CreateInstance(customizationType) as ICustomization;
var fixture = new Fixture();
fixture.Customize(new AutoNSubstituteCustomization());
fixture.Customize(customization);
return fixture;
})
{
}
}
I also have a custom customization class that setups the common customization for the test methods in the same class.
public class RevenueProviderCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<IRevenueContextService>(() =>
{
var contextService = Substitute.For<IRevenueContextService>();
contextService.GetContext().Returns(fixture.Create<RevenueContext>());
return contextService;
});
fixture.Register<ICompanyService>(() =>
{
var companyService = Substitute.For<ICompanyService>();
companyService.Get(Arg.Any<Guid>()).Returns(fixture.Create<Company>());
return companyService;
});
}
}
Now, some of my tests depend on modifying specific properties in the objects returned by the services. So in some cases, I want to modify the RevenueContext and in some cases, I want to modify the Company data.
What I did was creating another object inside the test itself and modify the Returns of the service with the new object, like this:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(RevenueProvider sut, Company company, [Frozen]IRevenueContextService contextService)
{
var fixture = new Fixture();
RevenueContext context = fixture.Build<RevenueContext>().With(c => c.DepartmentId, null).Create();
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
But this doesn't work. The RevenueContext from the RevenueProviderCustomization is still used.
Does anyone know how I can override the return from the service? I don't want to setup the fixture one by one in my test, so I was hoping to be able to create a 'general setup' and modify as needed according to the test case.
UPDATE 1
Trying the answer from Mark, I changed the test to
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue([Frozen]IRevenueContextService contextService, [Frozen]Company company, RevenueProvider sut, RevenueContext context)
{
context.DepartmentId = null;
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
The problem is because the RevenueContext is called in the RevenueProvider constructor. So my modification to the DepartmentId happens after the call was made.
public RevenueProvider(IRevenueContextService contextService, ICompanyService companyService)
{
_contextService = contextService;
_companyService = companyService;
_company = GetCompany();
}
public double GetRevenue()
{
if (_hasDepartmentContext)
return _company.Departments.Single(d => d.Id == _departmentId).Revenue;
else
return _company.Revenue;
}
private Company GetCompany()
{
RevenueContext context = _contextService.GetContext();
if (context.DepartmentId.HasValue)
{
_hasDepartmentContext = true;
_departmentId = context.DepartmentId.Value;
}
return _companyService.Get(context.CompanyId);
}
Assuming that RevenueProvider essentially looks like this:
public class RevenueProvider
{
private readonly ICompanyService companySvc;
public RevenueProvider(ICompanyService companySvc)
{
this.companySvc = companySvc;
}
public object GetRevenue()
{
var company = this.companySvc.Get(Guid.Empty);
return company.Revenue;
}
}
Then the following test passes:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(
[Frozen]ICompanyService companySvc,
RevenueProvider sut,
Company company)
{
companySvc.Get(Arg.Any<Guid>()).Returns(company);
var actual = sut.GetRevenue();
Assert.Equal(company.Revenue, actual);
}
This scenario is exactly what the [Frozen] attribute is designed to handle. The various attributes that AutoFixture defines are applied in the order of the arguments. This is by design, because it enables you to pull out a few values from the argument list before you freeze a type.
In the OP, [Frozen] is only applied after sut, which is the reason the configuration of the mock doesn't apply within the SUT.
I'm using the VS2012 built-in Fakes framework.
This design question is related to the following post: Unit test won't "cover" simple get method. (c#)
I'm not certain how to design class for "IDbAccess" to successfully "fake" hitting the database.
Ex code (taken from previous post):
public class Foo : IFoo
{
IDbAccess db;
public Foo(IDbAccess db)
{
this.db = db;
}
public Dictionary<string,string> GetSomething(string xyz)
{
var result = new Dictionary<string,string>
db.commandText = "text..."
db.connection = conn;
result.Add(db.MethodWhatever(xyz));
return result;
}
}
Ex Test Method:
[TestMethod()]
public void GetSomething()
{
var dba = new StubIDbAccess();
var target = new Foo(dba);
var expected = new Dictionary<string, string>
{
{"blahKey","blahValue"}
};
// get something
var results = target.GetSomething("xyzstring");
// verify results
var actual = results.whatever;
CollectionAssert.AreEqual(expected,actual);
}
In order to "stub" IDbAccess, IDbAccess needs to be a class that inherits from IDbCommand. I'm just not sure how to implement it to avoid having to override everything in IDbCommand.
public interface IDbAccess : IDbCommand
{
...?
}