Unit testing a Func<Delegate> with Rhino Mocks throwing InvalidCastException with second Expect() invocation

旧城冷巷雨未停 提交于 2020-01-03 05:52:13

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!