Я пытаюсь настроить модульные тесты для своего кода Linq To SQL. В моем коде используется класс System.Data.Linq.Table (созданный дизайнером).

Поскольку этот класс запечатан, а конструктор является внутренним, он полностью невосприимчив к средам модульного тестирования, таким как Rhino Mocks. (Если вы не хотите изменить свой код для использования шаблона репозитория, чего я бы предпочел не делать.)

Typemock может (каким-то образом) издеваться над этим классом. (См. Пример здесь.)

Однако Typemock также стоит 800 долларов за лицензию. Я не думаю, что мой работодатель в ближайшее время к этому прибегнет.

Итак, вот в чем вопрос. Существуют ли какие-либо другие фреймворки для фиксации, которые не полагаются на интерфейсы для создания макетов?


Изменить: пример кода, который мне нужно протестировать:

public class UserDAL : IUserDAL
{
    private IDataClassesDataContext _ctx;
    public UserDAL()
    {
        string env = ConfigurationManager.AppSettings["Environment"];
        string connectionString = ConfigurationManager
                                  .ConnectionStrings[env].ConnectionString;
        _ctx = new DataClassesDataContext(connectionString);
    }
    public UserDAL(IDataClassesDataContext context)
    {
        _ctx = context;
    }
    public List<User> GetUsersByOrganization(int organizationId)
    {
        IOrderedQueryable<User> vUsers =
            (from myUsers in _ctx.Users
             where myUsers.Organization == organizationId
             orderby myUsers.LastName
             select myUsers);
        return vUsers.ToList();
    }
    public bool IsUserInOrganization(User user, int orgainzationID)
    {
        // Do some Dal Related logic here.

        return GetUsersByOrganization(orgainzationID).Contains(user);            
    }
}

Я сократил это, чтобы было легче читать. Идея в том, что у меня есть код (например, IsUserInOrganization, который вызывает другой метод (например, GetUsersByOrganization), который выполняет запрос Linq.

Я хочу провести модульное тестирование метода IsUserInOrganization. Сделайте это, мне нужно будет издеваться над _ctx.Users, который является классом Table (который запечатан и имеет внутренний конструктор).

5
Vaccano 8 Дек 2009 в 20:09
Два примечания относительно кода: 1. Тестирование IsUserInOrganization обычно должно проводиться отдельно от тестирования GetUsersByOrganization, за исключением интеграционного тестирования; они не делают то же самое. Тесты GetUsersByOrganization обычно включают покрытие конкретного использования в IsUserInOrganization. Без дополнительного кода в методе IsUserInOrganization нет причин для тестирования метода, поскольку тестирование GetUsersByOrganization в любом случае должно охватывать соответствующие случаи. В основном, на мой взгляд, в этом случае вы хотите протестировать не то, что нужно.
 – 
Mike Burton
8 Дек 2009 в 21:12
Один звонит другому. Не передавая его другому классу, как вы можете протестировать один, не вызывая другой?
 – 
Vaccano
8 Дек 2009 в 21:13
Вы не можете. Фактически, это запах кода.
 – 
Mike Burton
8 Дек 2009 в 21:24
Один метод вызывает другой? Как пахнет этот код?
 – 
Vaccano
8 Дек 2009 в 22:00
Этот один метод отвечает за две вещи и не может быть разложен. Вы 1) собираете группу пользователей и 2) проверяете наличие конкретного пользователя. Метод в том виде, в котором он написан, не нужен, это просто удобство. Сам по себе он не делает ничего ценного.
 – 
Mike Burton
9 Дек 2009 в 00:07

3 ответа

Лучший ответ

Ознакомьтесь с заглушками Microsoft, в которых простая предпосылка:

Замени любой метод .NET своим собственным делегатом!

И более подробное описание его возможностей (выделено мной).

Заглушки - это легкий фреймворк для тестовые заглушки и обходные пути в .NET, то есть полностью на основе делегатов, введите безопасный, обновляемый и исходный код сгенерировано. Заглушки были разработаны для обеспечения минимальные накладные расходы на Pex white анализ коробки, поддержка кода Автор контрактов и поощрять программные модели а не тесты записи / воспроизведения. Заглушки можно использовать в любом методе .NET, включая невиртуальные / статические. методы в запечатанных типах.

4
Vaccano 21 Дек 2010 в 19:23
Заглушки переименованы в "Кроты".
 – 
Peli
21 Мар 2010 в 06:52
-1, из-за попытки использовать для этого Кротов я обнаружил, что это очень сложно. В TypeMock это так: Mock mockDC = MockManager.Mock (typeof (CustomerServicesDataContext)); mockDC.ExpectGetAlways («Категории», mockCats); --- 2 строки кода (плюс создание объекта mockCats)!
 – 
jcollum
21 Дек 2010 в 01:49
1
@jcollum, это довольно тонкий аргумент в пользу отклонения ответа, но вы делаете, что хотите. Кстати, я никогда не говорил, что это проще, чем TypeMock, и это отвечает на вопрос OP. Если у вас есть лицензия TypeMock, тогда хорошо для вас ... используйте ее. Но не думайте, что он есть у всех.
 – 
João Angelo
21 Дек 2010 в 13:14
@Joao: Это веская причина отклонить ответ: я думаю, что ответ неправильный. Однако тем временем я обнаружил, что ошибался, это можно сделать с помощью Moles - в сети очень мало способов объяснить, как это сделать. С TypeMock это проще. Думаю, вам придется отредактировать ответ, чтобы я снял свой голос против.
 – 
jcollum
21 Дек 2010 в 19:07
- как вы говорите, это вполне можно сделать с Кротами. Я даже разместил видео о том, как это сделать, на Dimecasts.net. (Он немного устарел и использует некоторые устаревшие части Moles, но код должен быть таким же). Я обнаружил, что Moles очень хороши и «готовы к прайм-тайму». Тем не менее, я думаю, что заглушки (их «нормальный» аналог для модульного тестирования) далеко не так хороши, как Rhino Mocks или NSubstitute. (ПРИМЕЧАНИЕ: я отредактировал ответ, если редактирование не должно выполняться исходным ответчиком, вы сможете изменить свой голос сейчас.)
 – 
Vaccano
21 Дек 2010 в 19:25

В этом случае есть два стандартных подхода к модульному тестированию:

1) Не тестируйте платформу - если зависимость находится от класса фреймворка, вы не пишете тесты, в которых проверяется это взаимодействие. Обычно это означает, что вы заменяете зависимость во время тестирования, но в вашем случае это, вероятно, означает, что вы вставляете саму таблицу.

2) Оберните платформу - если вам нужно протестировать что-то, что взаимодействует с платформой, напишите слой оболочки для соответствующих компонентов.

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

Что именно вас беспокоит при тестировании, которое вам нужно, чтобы напрямую имитировать / подменить этот класс?

Редактировать:

Похоже, вы не хотите переписывать код, чтобы его можно было больше тестировать. Именно здесь TypeMock превосходит всех, и это причина, по которой некоторые сторонники тестирования считают, что TypeMock может привести к проблемам. Однако это правильный инструмент для работы, если вы категорически отказываетесь от реструктуризации кода для обеспечения возможности тестирования.

Редактировать № 2:

Возможно, я слишком зациклен на этом, но давайте рассмотрим более проверенный шаблон:

Organization()
{
    HasUser(name)
}

OrganizationDAL
{
    Organization LoadOrganization(id)
}

OrganizationServiceFacade
{
   IsUserInOrganization(name, orgid)
   {
       return OrgDAL.LoadOrganization(id).HasUser(name)
   }
}

Тест естественного содержания организации для пользователя больше не должен зависеть от платформы, вы должны иметь возможность внедрить источник данных. OrganizationDAL отвечает только за загрузку организаций, а не за возврат информации об организациях (хотя есть способы поместить запросы на этот уровень, если это необходимо). OrganizationServiceFacade отвечает только за предоставление составных сервисов, которые должны удовлетворять имитацию и избегать необходимости в дополнительных модульных тестах (это интеграция или, возможно, даже цель принятия), поскольку это класс-оболочка. В зависимости от того, как вы строите организации, вы можете вводить данные, не полагаясь на конкретное представление о том, как эти данные работают.

2
Mike Burton 11 Дек 2009 в 02:44
Голосую за завертывание платформы. Вы не должны нести ответственность за проверку правильности работы ваших фреймворков.
 – 
Bryan Rowe
8 Дек 2009 в 20:24
К вопросу добавлено больше, чтобы показать, что меня беспокоит при тестировании.
 – 
Vaccano
8 Дек 2009 в 20:56

Вы можете рассмотреть возможность использования шаблона Repository, в основном это предложение Майка «обернуть платформу». С его помощью вы будете издеваться над IRepository, а не над DataContext.

http://blogs.microsoft.co.il/blogs/kim/archive/2008/11/14/testable-data-access-with-the-repository-pattern.aspx

-1
David 8 Дек 2009 в 21:09
Если вы перечитаете OP, вы увидите, что он там действительно упоминается.
 – 
Mike Burton
8 Дек 2009 в 21:47