I have an abstract class that I want to test. There is an abstract property in this class for my DAO, which I define in inherited classes.
public abstract class DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup
{
protected abstract IDeviceGroupDao<TDeviceGroup> DeviceGroupDao { get; }
public TDeviceGroup UpdateDeviceIndexes(Device device)
{
return DeviceGroupDao.GetDeviceGroup(device.Group.Id);
}
}
I want to test the Updatedeviceindexes method so I'm trying to mock a property called DeviceGroupDao.
[TestFixture]
[Category("Unit")]
public class DeviceGroupManagerBaseTests
{
private IFixture fixture;
private Mock<DeviceGroupManagerBase<DeviceGroup>> subject;
private Mock<IDeviceGroupDao<DeviceGroup>> deviceGroupDaoMock;
private DeviceGroupManagerBase<DeviceGroup> Manager => subject.Object;
[TestFixtureSetUp]
public void Init()
{
fixture = new Fixture().Customize(new AutoMoqCustomization());
deviceGroupDaoMock = fixture.Freeze<Mock<IDeviceGroupDao<DeviceGroup>>>();
subject = fixture.Freeze<Mock<DeviceGroupManagerBase<DeviceGroup>>>();
}
[Test]
public void TestUpdateDeviceIndexes()
{
var device = fixture.Create<Device>();
var deviceGroup = fixture.Create<DeviceGroup>();
deviceGroupDaoMock.Setup(x => x.GetDeviceGroup(It.IsAny<int>())).Returns(deviceGroup);
var result = Manager.UpdateDeviceIndexes(device);
// The resultDeviceGroup will not be contain a previously defined object
Assert.AreEqual(deviceGroup.Id, result.Id);
}
}
I also tried to add registration for my device object in this way:
fixture.Register(() => deviceGroup);
But I'm still getting a new object.
How can I mock IDeviceGroupDao<TDeviceGroup>?
Since DeviceGroupManagerBase is an abstract base class, you'll need a SUT Double. It's easiest to do if you make the DeviceGroupDao property public:
public abstract class DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup
{
public abstract IDeviceGroupDao<TDeviceGroup> DeviceGroupDao { get; }
public TDeviceGroup UpdateDeviceIndexes(Device device)
{
return DeviceGroupDao.GetDeviceGroup(device.Group.Id);
}
}
Otherwise, you'll need to use Moq's API for defining and overriding protected members, which is possible, but more work.
Then you'll need to override subject's DeviceGroupDao property:
subject.SetupGet(x => x.DeviceGroupDao).Returns(deviceGroupDaoMock.Object);
Here's the full test:
[TestFixture]
[Category("Unit")]
public class DeviceGroupManagerBaseTests
{
private IFixture fixture;
private Mock<DeviceGroupManagerBase<DeviceGroup>> subject;
private Mock<IDeviceGroupDao<DeviceGroup>> deviceGroupDaoMock;
private DeviceGroupManagerBase<DeviceGroup> Manager => subject.Object;
[OneTimeSetUp]
public void Init()
{
fixture = new Fixture().Customize(new AutoMoqCustomization());
deviceGroupDaoMock = fixture.Freeze<Mock<IDeviceGroupDao<DeviceGroup>>>();
subject = fixture.Freeze<Mock<DeviceGroupManagerBase<DeviceGroup>>>();
subject.SetupGet(x => x.DeviceGroupDao).Returns(deviceGroupDaoMock.Object);
}
[Test]
public void TestUpdateDeviceIndexes()
{
var device = fixture.Create<Device>();
var deviceGroup = fixture.Create<DeviceGroup>();
deviceGroupDaoMock.Setup(x => x.GetDeviceGroup(It.IsAny<int>())).Returns(deviceGroup);
var result = Manager.UpdateDeviceIndexes(device);
Assert.AreEqual(deviceGroup.Id, result.Id);
}
}
This now passes on my machine.
Because the DeviceGroupDao is protected you will need to find a way to access it externally. Create a stub that would allow you set it value.
public class DeviceGroupManagerBaseStub<TDeviceGroup>
: DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup {
private IDeviceGroupDao<TDeviceGroup> deviceGroupDao;
public DeviceGroupManagerBaseStub(IDeviceGroupDao<TDeviceGroup> deviceGroupDao) {
this.deviceGroupDao = deviceGroupDao;
}
protected override IDeviceGroupDao<TDeviceGroup> DeviceGroupDao {
get {
return deviceGroupDao;
}
}
}
You can then mock IDeviceGroupDao<TDeviceGroup> and inject it into the stub for your test.
Related
I have an interface Arbiter
public interface Arbiter
{
ContextData GetContextData();
}
I have a class that implements this interface.
public class ContextArbiter : Arbiter
{
ContextData m_data;
public CMBusContextArbiter()
:
base()
{
m_data = new ContextData();
}
public ContextData GetContextData()
{
return m_data;
}
}
I have another class that uses this interface
public class SelectData
{
private Arbiter m_Arbiter;
public SelectData(Arbiter Arbiter)
{
m_Arbiter = Arbiter;
}
public string RetrieveId()
{
return m_Arbiter.GetContextData().RouteId;
}
}
Now I want to unit test this class
public class SelectDataTest : UnitTestBase
{
private Mock<Arbiter> Arbiter;
private SelectData SelectData;
[OneTimeSetUp]
public void OneTimeSetup()
{
Arbiter= new Mock<Arbiter>();
SelectData = new SelectData(Arbiter);
}
}
But it seems that I can't pass the mock object to the SelectData class. It shows
Cannot convert Moq.Mock to Arbiter.
How can I get around this issue.
Use the Object property of the Mock<T> class to access the mocked object.
//...
Arbiter = new Mock<Arbiter>();
SelectData = new SelectData(Arbiter.Object);
//...
Reference Moq Quickstart
I am using AutoFixture in this instance to materialize objects containing a Mongo ObjectId, like so
Fixture fixture = new Fixture();
fixture.Register(ObjectId.GenerateNewId);
But I am doing this for every test. Is it possible to register this globall somehow for all tests?
There isn't a way to do this globally (or statically).
What I usually do is create a TestConventions class that contains all the customizations I want to apply to every test.
internal class TestConventions : CompositeCustomization
{
public TestConventions() :
base(
new MongoObjectIdCustomization())
{
}
private class MongoObjectIdCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register(ObjectId.GenerateNewId);
}
}
}
And then I apply these conventions to every test:
var fixture = new Fixture().Customize(new TestConventions());
If you're using the AutoFixture.XUnit2 (or AutoFixture.NUnit) plugin, you can reduce this boilerplate by defining an attribute that imports your test conventions:
public class MyProjectAutoDataAttribute : AutoDataAttribute
{
public MyProjectAutoDataAttribute() : base(
new Fixture().Customize(new TestConventions()))
{
}
}
And then apply it to your test cases:
[Theory, MyProjectAutoData]
public void SomeFact(SomeClass sut)
{
}
I created a convention class as suggested by #drcastro but I ended up creating a TestBase class which I inherit from in my Unit test class
public class TestBase
{
public IFixture GenerateNewFixture()
{
return new Fixture().Customize(new AutoFixtureConventions());
}
}
internal class AutoFixtureConventions : CompositeCustomization
{
public AutoFixtureConventions() :
base(
new MongoObjectIdCustomization())
{
}
private class MongoObjectIdCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register(ObjectId.GenerateNewId);
}
}
}
You could also do something like this
public class FixtureWithFoo: Fixture
{
public FixtureWithFoo()
{
Customizations.Add(new FooCustomization());
//Or register something else
}
}
and then use it in your test
var fixture = new FixtureWithFoo();
I solved this by registering an ISpecimenBuilder as I needed to match on some criteria concerning PropertyInfo.
private class MongoObjectIdSpecimenBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
if (request is PropertyInfo info
&& info.PropertyType == typeof(ObjectId)
&& ...)
return ObjectId.GenerateNewId().ToString();
return new NoSpecimen();
}
}
// register the builder
AutoFixture.Customizations.Add(new MongoObjectIdSpecimenBuilder());
Here is what I am trying to do:
public class MyTests
{
private IFixture _fixture;
public MyTests()
{
_fixture = new Fixture();
_fixture.Customize<Thing>(x => x.With(y => y.UserId, 1));
}
[Theory, AutoData]
public void GetThingsByUserId_ShouldReturnThings(IEnumerable<Thing> things)
{
things.First().UserId.Should().Be(1);
}
}
I would expect the IEnumerable<Thing> things parameter passed into the test to each have a UserId of 1 but this is not what happens.
How can I make this so?
You can do that by creating a custom AutoData attribute derived-type:
internal class MyAutoDataAttribute : AutoDataAttribute
{
internal MyAutoDataAttribute()
: base(
new Fixture().Customize(
new CompositeCustomization(
new MyCustomization())))
{
}
private class MyCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Thing>(x => x.With(y => y.UserId, 1));
}
}
}
You may also add other Customizations. Just keep in mind that the order matters.
Then, change the test method to use MyAutoData attribute instead, as shown below:
public class MyTests
{
[Theory, MyAutoData]
public void GetThingsByUserId_ShouldReturnThings(IEnumerable<Thing> things)
{
things.First().UserId.Should().Be(1);
}
}
In the following example, I want to test the TestMe.DoSomething() function.
I want to mock the ISomething interface that is used within this method and make it return different values (depending on the specific unit test.)
In real life the ISomething interface winds up calling out to expensive 3rd party resources -- I definitely don't want to just call a real ISomething.
Here is the example structure:
class TestMe
{
public void DoSomething()
{
ISomething s = SomethingFactory();
int i = s.Run();
//do things with i that I want to test
}
private ISomething SomethingFactory()
{
return new Something();
}
}
interface ISomething
{
int Run();
}
class Something : ISomething
{
public int Run()
{
return 1;
}
}
Here is code that doesn't work:
var fakeSomething = new Mock<ISomething>();
var testMe = new TestMe();
Mock.Get(testMe).Setup(p => p.SomethingFactory()).Returns(fakeSomething.Object);
testMe.DoSomething();
Because SomethingFactory() is private, I cannot set the return value from that method to be what I want.
Any advice on how I can solve this?
Make the factory a full interface / class and remove the SomethingFactory method from TestMe.
public interface ISomethingFactory {
ISomething MakeSomething();
}
public sealed class SomethingFactory {
public ISomething MakeSomething() {
return new Something();
}
}
class TestMe
{
private readonly ISomethingFactory _somethingFactory;
public TestMe(ISomethingFactory somethingFactory) {
_somethingFactory = somethingFactory;
}
public void DoSomething()
{
ISomething s = _somethingFactory.MakeSomething();
int i = s.Run();
//do things with i that I want to test
}
}
This will allow you to mock ISomethingFactory to return a mock of ISomething.
While I think you may protest this solution as too drastic a change, I think its better than making a class that's not sealed with a members who's only reason for being virtual is for testing.
You can inject your dependency. If you don't want to break all your callers you can add two constructors and use the one that lets you inject fake in tests
class TestMe
{
private readonly ISomething something;
TestMe() : this(new RealSomething()
{
}
TestMe(ISomething sth)
{
something = sth;
}
public void DoSomething()
{
ISomething s = SomethingFactory();
int i = s.Run();
//do things with i that I want to test
}
private ISomething SomethingFactory()
{
return new Something();
}
}
Second way would be to change the
SomethingFactory
method to protected virtual and override it in derived class and use that class instead, or to setup
class TestableTestMe : TestMe
{
private readonly ISomething something;
TestableTestMe(ISomething testSpecific)
{
something = testSpecific;
}
public void DoSomething()
{
ISomething s = SomethingFactory();
int i = s.Run();
//do things with i that I want to test
}
protected override ISomething SomethingFactory()
{
return something;
}
}
This technique is called "extract and override"
Changing SomethingFactory() to be protected virtual allows you to use Moq.Protected to access the method by its name:
public class TestMe
{
public void DoSomething()
{
ISomething s = SomethingFactory();
int i = s.Run();
//do things with i that I want to test
}
protected virtual ISomething SomethingFactory()
{
return new Something();
}
}
public interface ISomething
{
int Run();
}
public class Something : ISomething
{
public int Run()
{
return 1;
}
}
So you can run this test:
var fakeSomething = new Mock<ISomething>();
fakeSomething.Setup(p => p.Run()).Returns(2);
var testMe = new Mock<TestMe>();
testMe.Protected().Setup<ISomething>("SomethingFactory").Returns(fakeSomething.Object);
testMe.Object.DoSomething();
public class stubBaseTx : BaseTxFlowOperations
{
private MockRepository mocks;
private ITransaction mockITransaction;
public stubBaseTx()
{
mocks = new Rhino.Mocks.MockRepository();
mockITransaction = mocks.DynamicMock<ITransaction>();
mocks.ReplayAll();
}
protected override ITransaction FlowProperty_Transaction
{
get
{
return mockITransaction;
}
}
}
public class StubWithdrFlowISONet :WithdrawalFlowISONet
{
private MockRepository mocks;
private bool FlowProperty_PINReAv = false;
public StubWithdrFlowISONet()
{
mocks = new Rhino.Mocks.MockRepository();
mocks.ReplayAll();
stubBaseTx obj = new stubBaseTx();
base.CreateCRMManager();
}
protected override bool FlowProperty_PINRetriesAvailable
{
get
{
return FlowProperty_PINReAv;
}
}
}
Here WithdrawalFlowISONet is inhereted from WithdrawalFlowOperation class and WithdrawalFlowOperation is inhereted from BaseTxFlowOperations class , now i have FlowProperty_Transaction
property in BaseTxFlowOperations which i have to pass to WithdrawalFlowISONet class but it is readonly which can be modified in BaseTxFlowOperations only now i have created stubBaseTx class just to modify FlowProperty_Transaction
property , so how can i assign stubBaseTx class to WithdrawalFlowISONet class so that it should work as a base for WithdrawalFlowISONet class.
[C#]
Thanks,
Nishant