Служба модульного тестирования с вызовом WCF (MSUnit + Moq) - PullRequest
5 голосов
/ 21 декабря 2009

Я новичок в Mocking и немного знаком с модульным тестированием и, наконец, решил укусить пулю в новом проекте, начинающемся с жесткого подхода TDD. Однако у меня есть один класс обслуживания и метод, к которым мне нужно ретроспективно добавлять тесты, как это было продвинуто из прототипа.

Я не знаю, с чего начать, хотя в данном конкретном тесте используются следующие классы и методы:

public class PageService : IPageService
{
    private readonly ITestService testServiceClient;

    public PageService(ITestService testServiceClient)
    {
        this.testServiceClient = testServiceClient;
    }

    public Page GetPage(Guid websiteId, string pageKey)
    {
        Page builtPage = null;

        // WCF SERVICE CALL I DO NOT WANT EXECUTING WHEN RUNNING UNIT TEST
        // BUT RATHER WANT A BLANK NEW INSTANCE OF "PAGE" CREATED USING MOQ??
        var page = testServiceClient.GetPage(websiteId, pageKey);

        if (page == null)
            return null;

        builtPage = new Page();

        [code here to build builtPage if input params ok] ...

        return builtPage;
    }
}

То, что я пытаюсь сделать, это написать один тест, из этого, я надеюсь, я могу развернуть все варианты GetPage(...) тестов, но для первого просто проверить, если действительные websiteId и pageKey пройдены in, если это так, верните действительный экземпляр Page и подтвердите значение true для модульного теста.

testServiceClient является клиентом службы WCF, это было включено в оператор using() ранее, но я переместил его из этого в надежде запустить его с внедрением зависимости, так как считаю, что это будет первым необходимым шагом для тестирования, как я понимаю из-за того, что я должен дать ему подделку / издеваться? Вместо этого wcf клиент, где testServiceClient.GetPage() возвращает известный набор данных в памяти? Надеюсь, я на правильном пути.

Итак, вот мои первоначальные чертежи моего модульного теста (я использую Moq Framework, Setup() - это новая версия Expect(), если вы не использовали последнюю версию Moq):

/// <summary>
/// Tests service returns a valid instance of type `Page` when a valid website and valid page key is tested.
/// </summary>
[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
    // Arrange
    Page page = null;

    // Act
    var newPage = new Page() { Title = "Mocked Version!?"};

    testServiceClient = new Mock<ITestService>();
    testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);

    service = new PageService(testServiceClient.Object);
    page = service.GetPage(websiteId, "about-us");

    // Assert
    Assert.IsInstanceOfType(page, typeof(Page), "Object was not of expected instance type.");
}

Я понятия не имею, куда идти дальше или я на правильном пути? Я могу подтвердить, что выше не имеет синтаксических ошибок, и я получаю исключение:

System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetPage(websiteId, "about-us").

Все, что я знаю, это то, что я хочу, чтобы мой service.GetPage(...) возвратил новый экземпляр, поскольку websiteId и pageKey были действительны, однако я не хочу, чтобы он использовал настоящий вызов testServiceClient.GetPage() WCF ... надеюсь, я правильно понимаю идею насмешек. Правильно ли я сказал это через Moq, когда вы используете testServiceClient.GetPage в этой службе, на самом деле просто возвращаете новый экземпляр страницы?

Любые разъяснения приветствуются! Спасибо, ребята!

1 Ответ

4 голосов
/ 21 декабря 2009

Я бы сказал, что вы на правильном пути. Если ITestService действительно является интерфейсом (как указано его именем), вы сможете его смоделировать.

Однако, когда вы определяете свои настройки, Moq должен быть в состоянии определить, какой метод вы имели в виду, и кажется, что вы как-то указываете метод, которого нет в интерфейсе.

Вы не показывали нам интерфейс ITestService, а также мы не знаем тип переменной websiteId.

Если вы внимательно посмотрите на метод установки, вы увидите, что это действительно универсальный метод, поэтому при вызове его без универсальных параметров происходит вывод типа.

Я предполагаю, что объявление websiteId как-то противоречит объявлению GetPage. Если, например, websiteId был объявлен как object, Moq будет искать метод с такой подписью:

Page GetPage(object x, string y);

что не совпадает с

Page GetPage(Guid x, string y);

В любом случае, если вам удастся запустить программу установки, ваша базовая идея о модульном тестировании выглядит хорошо. Вы можете сделать больше, чем просто заявив, что экземпляр не равен NULL, потому что Mock гарантирует, что возвращаемый экземпляр будет таким же, как экземпляр, который вы установили изначально:

[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
    // Arrange
    Page page = null;

    // Act
    var newPage = new Page() { Title = "Mocked Version!?"};

    testServiceClient = new Mock<ITestService>();
    testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);

    service = new PageService(testServiceClient.Object);
    page = service.GetPage(websiteId, "about-us");

    // Assert
    Assert.AreEqual(newPage, page);
}

Обратите внимание на гораздо более ценный Assert.

...