Невозможно создать класс Mock для внутреннего типа с помощью Rhino Mocks

Я использую Rhino Mocks в качестве фреймворка для имитации модульного тестирования.

У меня есть класс Subject, который я хочу протестировать. Он зависит от IStore.

IStore определяется следующим образом:

//internal interface : has InternalsVisible to both "Subject" 
//and "StoreTests" class namespaces
internal interface IStore {
    void Store(string name);
    //other methods
}

а класс Subject определяется следующим образом:

class Subject : IStore {
    private IStore internalStore;

    //constructor injection
    void Subject(IStore store) {
        internalStore = store;
    }

    void Store(string name) {
        internalStore.Store(name);
    }

    //other methods
}

Мой тестовый класс с использованием RhinoMocks выглядит следующим образом:

//test class
class StoreTests {
    Subject subject = new Subject();

    [Test]
    public StoreTest() {
        //Arrange
        var mockStore = MockRepository.GenerateMock<IStore>();
        string testName = "test";
        mockStore.Expect(x => x.Store(testName)).Returns(null);

        //Act
        subject.Store(testName);

        //Assert
        mockStore.VerifyAllExpectations();
    }

    //other test methods
}

В моей настройке интерфейс определен как внутренний, и для него установлен InternalsVisible как для класса Subject, так и для класса StoreTests. Однако, когда тестовый пример выполняется, он генерирует исключение в var mockStore = MockRepository.GenerateMock (); говоря, что IStore не является общедоступным, и поэтому он не может создать Mock.

Я думаю, это потому, что IStore не является публичным. Однако, поскольку я установил InternalsVisibleTo в dll IStore, будет ли для StoreTests достаточно создать макет для этого класса?

Теперь я думаю, что эту проблему можно решить, сделав интерфейс IStore общедоступным. Однако, учитывая, что это не вариант для меня, есть ли другой способ создать макет для IStore?


person Santhosh    schedule 28.07.2011    source источник


Ответы (3)


Вы пытались сделать внутреннюю часть сборки видимой для моков Rhino?

[assembly: InternalsVisibleTo ("DynamicProxyGenAssembly2")]

Подробнее см. Rhino Mocks Internal Members.

Когда класс имитируется, во время выполнения создается новый класс, производный от имитируемого класса. Этот сгенерированный класс находится в отдельной временной сборке, которая называется DynamicProxyGenAssembly2. Итак, атрибут InternalsVisibleTo должен быть установлен в целевой сборке, чтобы разрешить доступ к ее внутренним членам из временной сборки; в противном случае фиктивный объект не может переопределить внутренний член, поскольку у него нет доступа к нему (именно поэтому фиктивный метод должен быть помечен как виртуальный). Обратите внимание, что это верно, даже если модульный тест и тестируемый класс находятся в одной сборке.

Итак, вам необходимо убедиться, что сборка целевого класса делает свои внутренние компоненты видимыми для сборки прокси как таковой (например, в AssemblyInfo.cs):

person alun    schedule 28.07.2011
comment
Просто потратил пару часов, пытаясь понять, что мне не хватает. Лучше поздно, чем никогда. Спасибо за информацию. - person Rich; 28.09.2018

Да, этого должно быть достаточно, чтобы добавить следующее в файл AssemblyInfo.cs тестируемой сборки:

[assembly: InternalsVisibleTo("Tests.Assembly.Name")]
[assembly: InternalsVisibleTo("NUnit.Framework")]
[assembly: InternalsVisibleTo("Rhino.Mocks, PublicKey=00240000048000009400000006020000002400005253413100040000010001009D1CF4B75B7218B141AC64C15450141B1E5F41F6A302AC717AB9761FA6AE2C3EE0C354C22D0A60AC59DE41FA285D572E7CF33C320AA7FF877E2B7DA1792FCC6AA4EB0B4D8294A2F74CB14D03FB9B091F751D6DC49E626D74601692C99EAB7718ED76A40C36D39AF842BE378B677E6E4EAE973F643D7065241AD86ECC156D81AB")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
person sll    schedule 28.07.2011
comment
Этот ответ тоже прекрасен. Отметить другой как принятый только потому, что он предоставляет ссылку на дополнительную информацию в вики. - person Santhosh; 28.07.2011

Ну, на это можно было бы ответить, но для меня это не сработало.

Итак, вот что я сделал, чтобы он заработал (может помочь другим и даже мне в следующем проекте ...):

В меню «Инструменты» в Visual Studio: Внешние инструменты: Добавьте для имени, я поставил «LongStrongName», но укажите все, что считаете нужным:

(этот путь или где вам нужен sn.exe):

Command:
  C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\sn.exe
Arguments:
  -Tp $(TargetPath)

(Установите флажок, выведите в «Использовать окно вывода»)

Теперь вы можете щелкнуть проект, затем перейти к инструментам и перейти в меню «LongStrongName»:

и VS выведет:

Public key is       0240000048000009400000006020000002400005253413100040000010001009badbe86c32ec0
ec429f0b3909*********

Public key token is 6ccc051********

Откройте файл assembly.cs и добавьте:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

добавить любые сборки, которые вам нужны, и вуаля (мне пришлось поставить несколько сборок).

person Fx Mzt    schedule 03.08.2012