Невозможно создать класс 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?

Ответ 1

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

[assembly: InternalsVisibleTo ("DynamicProxyGenAssembly2")]

Подробные сведения см. В разделе Внутренние члены Rhino Mocks.

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

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

Ответ 2

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

[assembly: InternalsVisibleTo("Tests.Assembly.Name")]
[assembly: InternalsVisibleTo("NUnit.Framework")]
[assembly: InternalsVisibleTo("Rhino.Mocks, PublicKey=00240000048000009400000006020000002400005253413100040000010001009D1CF4B75B7218B141AC64C15450141B1E5F41F6A302AC717AB9761FA6AE2C3EE0C354C22D0A60AC59DE41FA285D572E7CF33C320AA7FF877E2B7DA1792FCC6AA4EB0B4D8294A2F74CB14D03FB9B091F751D6DC49E626D74601692C99EAB7718ED76A40C36D39AF842BE378B677E6E4EAE973F643D7065241AD86ECC156D81AB")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

Ответ 3

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

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

В меню "Инструмент" в 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")]

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