问题
I'm unit testing a class that gets some parameters injected by Autofac.
Some of the parameters are Func<Delegate>
. This allows me to create multiple delegates to use. Refer to this Autofac Wiki page if you need a better description.
Here's part of the class.
public class CreateProductCommand : TransactionalDBCommandBase<ProductImpl>
{
public delegate CreateProductCommand Factory(ProductInfo info, IAppSecurityContext context);
private ProductInfo _info;
private Func<SaveTextMasterCommand.Factory> _saveTextMasterCommandFactory;
private Func<SaveTextValueCommand.Factory> _saveTextValueCommandFactory;
private SaveProductCommand.Factory _saveProductCommand;
public CreateProductCommand(ProductInfo info, Func<SaveTextMasterCommand.Factory> saveTextMasterCommandFactory,
Func<SaveTextValueCommand.Factory> saveTextValueCommandFactory, SaveProductCommand.Factory saveProductCommand, IAppSecurityContext context)
{
this._info = info;
this._saveTextMasterCommandFactory = saveTextMasterCommandFactory;
this._saveTextValueCommandFactory = saveTextValueCommandFactory;
this._saveProductCommand = saveProductCommand;
this.CurrentContext = context;
}
public override ProductImpl Execute(IDataTransaction dataTrans)
{
//More code here
this._saveTextMasterCommandFactory().Invoke(SomeParam,SomeParam2).Execute(dataTrans);
//Some time later
this._saveTextMasterCommandFactory().Invoke(SomeDiffParam,SomeDiffParam2).Execute(dataTrans);
}
}
The test class looks like this. The SetUp is HUGE. I'll align the left side of the code block where the issue is.
[TestFixture]
public class CreateProductCommandTests
{
private IDataTransaction _dtMock;
private IDataAccessAdapter _daaMock;
private Func<SaveTextMasterCommand.Factory> stmfMock;
private Func<SaveTextValueCommand.Factory> stvfMock;
private SaveProductCommand.Factory saveProductDelMock;
private ProductInfo info;
private IAppSecurityContext context;
[SetUp]
public void SetUp()
{
this._dtMock = MockRepository.GenerateMock<IDataTransaction>();
this._daaMock = MockRepository.GenerateMock<IDataAccessAdapter>();
this._dtMock.Expect(m => m.DataAccessAdapter).Repeat.Any().Return(this._daaMock);
stvfMock = MockRepository.GenerateMock<Func<SaveTextValueCommand.Factory>>();
stmfMock = MockRepository.GenerateMock<Func<SaveTextMasterCommand.Factory>>();
context = new AppSecurityContext() { LanguageID = 1 };
info = new ProductInfo()
{
CatalogNumber = "CatalogNumber",
BrandID = 1,
ProductDescription = "ProductDescription",
ProductName = "ProductName"
};
//Mock the command
var nameTextMaster = new TextMasterImpl() { AltTextMasterID = new Guid().ToString("N"), IsCoreAppText = false, TextMasterID = 1 };
var nameTextMasterMock = MockRepository.GenerateMock<SaveTextMasterCommand>(null, null);
nameTextMasterMock.Expect(m => m.Execute(Arg<IDataTransaction>.Is.Equal(this._dtMock))).Return(nameTextMaster);
//Mock the Delegate that creates it.
var nameTextMasterFactoryMock = MockRepository.GenerateMock<SaveTextMasterCommand.Factory>();
nameTextMasterFactoryMock.Expect(m => m(Arg<TextMasterImpl>.Is.Anything, Arg<IAppSecurityContext>.Is.Anything)).Return(nameTextMasterMock);
//This call here is fine. Passes with no problem.
stmfMock.Expect(m => m()).Return(nameTextMasterFactoryMock);
//NameTextValue Mocking.
var nameTextValue = new TextValueImpl() { LanguageID = 1, ContentText = "NameTextValue", TextMasterID = 1, TranslationStatus = 0, TextValueID = 1 };
var nameTextValueMock = MockRepository.GenerateMock<SaveTextValueCommand>(null, null);
nameTextValueMock.Expect(m => m.Execute(Arg<IDataTransaction>.Is.Equal(this._dtMock))).Return(nameTextValue);
var nameTextValueFactoryMock = MockRepository.GenerateMock<SaveTextValueCommand.Factory>();
nameTextValueFactoryMock.Expect(m => m(Arg<TextValueImpl>.Matches(n => n.TextMasterID == nameTextMaster.TextMasterID && n.ContentText == info.ProductName),
Arg<IAppSecurityContext>.Is.Anything)).Return(nameTextValueMock);
stvfMock.Expect(m => m()).Repeat.Once().Return(nameTextValueFactoryMock);
//DescriptionTextMaster Mocking
var descTextMaster = new TextMasterImpl() { AltTextMasterID = new Guid().ToString("N"), IsCoreAppText = false, TextMasterID = 2 };
var descTextMasterMock = MockRepository.GenerateMock<SaveTextMasterCommand>(null, null);
descTextMasterMock.Expect(m => m.Execute(Arg<IDataTransaction>.Is.Equal(this._dtMock))).Return(descTextMaster);
//Delegate mock
var descTextMasterFactoryMock = MockRepository.GenerateMock<SaveTextMasterCommand.Factory>();
descTextMasterFactoryMock.Expect(m => m(Arg<TextMasterImpl>.Is.Anything, Arg<IAppSecurityContext>.Is.Anything)).Return(descTextMasterMock);
//THIS call fails with an InvalidCastException
stmfMock.Expect(m => m()).Return(descTextMasterFactoryMock);
var descTextValue = new TextValueImpl() { LanguageID = 1, ContentText = "DescTextValue", TextValueID = 2, TextMasterID = 2, TranslationStatus = 0 };
var descTextValueMock = MockRepository.GenerateMock<SaveTextValueCommand>(null, null);
descTextValueMock.Expect(m => m.Execute(Arg<IDataTransaction>.Is.Equal(this._dtMock))).Return(descTextValue);
var descTextValueFactoryMock = MockRepository.GenerateMock<SaveTextValueCommand.Factory>();
descTextValueFactoryMock.Expect(m => m(Arg<TextValueImpl>.Matches(n => n.TextMasterID == descTextMaster.TextMasterID && n.ContentText == info.ProductDescription),
Arg<IAppSecurityContext>.Is.Anything)).Return(descTextValueMock);
stvfMock.Expect(m => m()).Repeat.Once().Return(descTextValueFactoryMock);
var product = new ProductImpl() { ProductNameTextID = nameTextMaster.TextMasterID, DescriptionTextID = descTextMaster.TextMasterID, CatalogNumber = info.CatalogNumber, ProductID = 1 };
var saveProductCommandMock = MockRepository.GenerateMock<SaveProductCommand>(null, null);
saveProductCommandMock.Expect(m => m.Execute(Arg<IDataTransaction>.Is.Equal(this._dtMock))).Return(product);
saveProductDelMock = MockRepository.GenerateMock<SaveProductCommand.Factory>();
saveProductDelMock.Expect(m => m(Arg<ProductImpl>.Is.Equal(product), Arg<IAppSecurityContext>.Is.Anything)).Return(saveProductCommandMock);
}
}
Exception is: Unable to cast object of type 'ProxyDelegate_Factory_3Proxyef78e79dacee4c759351a5ffaa933f85' to type 'Factory'.
I'm not exactly sure how to get this fixed.
回答1:
This suggestion isn't particularly inspired by the exception message you receive, so it may not help. It seems to me that you haven't given enough information to the mock repository, however:
stmfMock.Expect(m => m()).Return(nameTextMasterFactoryMock);
//...
stmfMock.Expect(m => m()).Return(descTextMasterFactoryMock);
You've got the same mock expecting the same method to be called (i.e., Invoke
), and you're telling it to return two different things. How about this:
stmfMock.Expect(m => m()).Repeat.Once().Return(nameTextMasterFactoryMock);
//...
stmfMock.Expect(m => m()).Repeat.Once().Return(descTextMasterFactoryMock);
来源:https://stackoverflow.com/questions/10076819/unit-testing-a-funcdelegate-with-rhino-mocks-throwing-invalidcastexception-wit