Сопоставление параметров эталонного типа с помощью настройки Moq

У меня проблема, похожая на ту, что задана здесь или здесь, но решения, похоже, не применимы в моем случае.

Рассмотрим следующие классы:

public interface IProductsWebService
{
    ICObjectLang[] GetClassLevel(getClassLevelLang criteria);
}

// the rest of this class was automaticaly generated as web service reference
public partial class getClassLevelLang : IEquatable<getClassLevelLang>
{
    public override bool Equals(object obj)
    {
        var other = obj as getClassLevelLang;

        return Equals(other);
    }

    public bool Equals(getClassLevelLang other)
    {
        if (this == other)
        {
            return true;
        }

        if (other == null)
        {
            return false;
        }

        return CID == other.CID &&
               accessCode == other.accessCode &&
               classCode == other.classCode &&
               depth == other.depth &&
               language == other.language &&
               partyCode == other.partyCode &&
               refId == other.refId;
    }

    public override int GetHashCode()
    {
        var hash = 531;

        hash += CID != null ? CID.GetHashCode() : 1;
        hash += accessCode != null ? accessCode.GetHashCode() : 1;
        hash += classCode != null ? classCode.GetHashCode() : 1;
        hash += depth != null ? depth.GetHashCode() : 1;
        hash += language != null ? language.GetHashCode() : 1;
        hash += partyCode != null ? partyCode.GetHashCode() : 1;
        hash += refId != null ? refId.GetHashCode() : 1;

        return hash;
    }

    public override string ToString()
    {
        var str = new StringBuilder();

        str.AppendFormat("CID: {0}, ", CID);
        str.AppendFormat("accessCode: {0}, ", accessCode);
        str.AppendFormat("classCode: {0}, ", classCode);
        str.AppendFormat("depth: {0}, ", depth);
        str.AppendFormat("language: {0}, ", language);
        str.AppendFormat("partyCode: {0}, ", partyCode);
        str.AppendFormat("refId: {0}", refId);

        return str.ToString();
    }
}

И следующий код для тестирования (список calls предназначен только для отладки):

private Mock<IProductsWebService> productsService;
private IProductsImportProcess target;

private List<getClassLevelLang> calls = new List<getClassLevelLang>();

[TestMethod]
public void RecursiveDownloadTest()
{
        //other mocks (configuration, log, categoryService and configurationService) set here

        target = new ProductsImportProcess(
            configuration.Object, log.Object, categoryService.Object,
            productsService.Object, configurationService.Object);

        productsService = new Mock<IProductsWebService>(MockBehavior.Strict);

        var root1 = new Category
        {
            CategoryID = "root1",
            SubCategories = new List<Category>
                                                {
                                                    new Category
                                                        {
                                                            CategoryID = "cat1.1",
                                                            SubCategories = new List<Category>
                                                                                {
                                                                                    new Category
                                                                                        {CategoryID = "cat1.1.1"}
                                                                                }
                                                        },
                                                    new Category
                                                        {
                                                            CategoryID = "cat1.2"
                                                        }
                                                }
        };
        var root2 = new Category { CategoryID = "root2" };

        setupProductsServiceCall("tree1", root1, true);
        setupProductsServiceCall("tree1", root1.SubCategories.First().SubCategories.First());
        setupProductsServiceCall("tree2", root2, true);

        target.Execute();

        productsService.VerifyAll();
    }

    private void setupProductsServiceCall(string treeCode, Category category, bool isRoot = false)
    {
        var config = configuration.Object;

        var criteria = new getClassLevelLang
                           {
                               CID = isRoot ? null : category.CategoryID,
                               language = "all",
                               partyCode = "something",
                               depth = "1",
                               classCode = treeCode,
                               accessCode = "xyz"
                           };
        var productsNode = TestUtils.CreateAbbProductsNode(category);

        productsService.Setup(mock => mock.GetClassLevel(It.Is<getClassLevelLang>(c => c.Equals(criteria)))).
            Callback<getClassLevelLang>(c => calls.Add(c)).        //added for debuging purposes only
            Returns(productsNode.objectAttributes).
            Verifiable();
}

Приведенный выше тест не проходит со следующим исключением:

Test method ProductsImport.Console.Test.ProductsImportProcessUnitTest.RecursiveDownloadTest threw exception: 
Moq.MockVerificationException: The following setups were not matched:
    IProductsWebService mock => mock.GetClassLevel(It.Is<getClassLevelLang>(c => c.Equals(CID: , accessCode: xyz, classCode: tree1, depth: 1, language: all, partyCode: something, refId: )))
    IProductsWebService mock => mock.GetClassLevel(It.Is<getClassLevelLang>(c => c.Equals(CID: cat1.1.1, accessCode: xyz, classCode: tree1, depth: 1, language: all, partyCode: something, refId: )))
    IProductsWebService mock => mock.GetClassLevel(It.Is<getClassLevelLang>(c => c.Equals(CID: , accessCode: xyz, classCode: tree2, depth: 1, language: all, partyCode: something, refId: )))
Result StackTrace:    
    at Moq.Mock.VerifyAll()

Я уверен, что вызывается ProductsWebService.GetClassLevel, а getClassLevelLang.Equals нет (проверено отладчиком). Что еще более странно, я проверил фактическое значение calls непосредственно перед вызовом списка VerifyAll(), и он пуст.


person Marek    schedule 04.03.2013    source источник


Ответы (1)


Ваш макет productsService не внедряется в ваш ProductsImportProcess, поэтому не может перехватывать вызовы, сделанные на реальном IProductsWebService. Как вы создаете экземпляр объекта IProductsWebService в своем коде?

person levelnis    schedule 04.03.2013
comment
На самом деле он вводится в код выше - конструктором: target = new ProductsImportProcess(..., productsService.Object, ...); В моем приложении он вводится контейнером IoC (Ninject) - person Marek; 04.03.2013
comment
Хорошо, но затем, в соответствии с приведенным выше кодом, вы создаете его экземпляр ПОСЛЕ того, как вы вводите его, поэтому, когда он будет введен в ваш тест, он будет нулевым. - person levelnis; 04.03.2013
comment
Да, вы поняли - я столько раз менял код после получения первой такой ошибки (до реализации пользовательской логики равенства в getClassLevelLang), что пропустил это. Ошибка новичка... Большое спасибо! - person Marek; 05.03.2013