问题
I am trying to unit test a class that uses factory injection. I have a class that instantiates two copies of the same object (with different config) to control hardware. I'm trying to test the behaviour of the classes while simulating the hardware calls.
I've injected a set of factory delegates into the constructors so that the class can instantiate the hardware classes as required. However I just can't work out how to control or create factory methods within the Autofac.Extras.Moq package. It seems that this functionality isn't supported in the package.
I'm looking for an equivalent call to :
mock.Provide<IHWController>(//created by factory delegate)
I want to create a specific mock object with behaviour, based on the parameters used to instantiate the HWcontroller. Is what I'm trying to do even possible?
class SystemUnderTest
{
SystemUnderTest(Ia a, Ib b, Ic c,
/** 15 other things **/
Func<Func<Uri, IHwController>, HwType, IHwManager> HwManagerFactory,
Func<Uri, IHwController> HwControllerFactory)
{
}
}
class HwManager()
{
public Func<HwType, Func<Uri, HwController>, HwManager> Factory;
public HwManager(HwType type, Func<Uri, HwController> ControlFactory)
{
//Constructor
}
}
The code I'm unit testing creates Managers of controllers. The controller is the hardware layer, but I'm testing complex (coupled) behaviour inside the manager. Therefore, I'm trying to work out how to mock the Func<Uri, HwController> ControlFactory
so that it returns my setup mock objects so that I can probe the behaviour of the manager.
My system under test creates a concrete instantiation of the HWManager. I realise in a perfect scenario I would test the HwManager and SUT separately, but I'm specifically testing the integration of the two components.
I'd like to configure the autofac to control the delegate factory. If this isn't possible, then I can manually setup the SUT, but then I don't get any value from the autofac helper.
回答1:
I usually just create a Func that returns my mocked instance e.g.
var controller = mock.Provide<IHWController>();
var manager = new HwManager(something, (uri) => controller);
If the factory is expressing "given a Uri I will provide a controller", the lamda in my example above satisfies that statement.
As an aside, you should express your factories using interfaces, not concrete classes. It makes it a lot harder to unit test when the factories are producing concrete classes instead of interfaces (which can always be mocked) e.g.
// IHwController is the product of the factory instead of HwController
public HwManager(HwType type, Func<Uri, IHwController> ControlFactory)
回答2:
If anyone gets stuck on this in the future, the key is to create a func that matches the constructor func, customised to provide the appropriate mocks on each invokation (e.g. via an internal counter).
You can then use the mock.Provide() syntax, providing a func that matches the constructor func with your created func above. This will then be invoked correctly allowing you to control the mocks appropriately.
来源:https://stackoverflow.com/questions/29639360/using-autofac-and-moqs-with-delegate-factories