Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775

Тест простого метода

02.06.2025, 21:16. Показов 7990. Ответов 100
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Решил попробовать написть тест для одного из методов, где без тестов реально иногда баги вылезают при доработках.

Метод простой - получает на вход подключение к БД, возвращает в виде многоуровневой структуры объектов информацию обо всей структуре БД (таблицы, колонки, индексы, связи, триггеры и т.п.).

Общая структура теста в итоге получилась такая:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    [Fact]
    public void ParseDbSchemeTest()
    {
        //
        //Подготовка окружения.
 
        //Подключение к тестовому SQL-серверу.
        using var conn = CreateConnection();
 
        //Создание тестовой БД, создание структуры БД, покрывающей все сценарии.
        var dbName = "sample_db";
        PreapareTestDb(conn, dbName);
 
        //Структура БД для сравнения (загрузка из JSON, например).
        Database expectedDbStructure = PrepareExpected();
 
        //
        //Выполнение тестируемого метода.
        //* через information_schema считывает структуру БД (таблицы, колонки, индексы и т.п.)
        //* и раскладывает её в многоуровевую структуру объктов.
        Database actualDbStructure = new DatabaseParser().Parse(conn, dbName);
        DropTestDb(conn, dbName);
 
        //
        //Проверка результата.
        //* тут полное сравнение структур на всю глубину.
        Assert.True(expectedDbStructure.Equals(actualDbStructure));
    }
Технически, этот тест закрывает все сценарии, когда кто-то вносит некорректные изменения в:
1. SQL-скрипты, которые делают выборку из 'information_schema' в методе 'Parse'.
2. Логику раскладывания данных из 'information_schema' в экземпляр 'Database'.

Однако, если кто-то из разработчиков дополнит обозначенные два пункта новым функционалом, не затронув существующий, тест продолжит корректно продоходить, но при этом фактически не будет покрывать все возможные сценарии метода 'DatabaseParser.Parse'.

Получается, что нужен ещё один тест, который будет контролировать, что структура типа 'Database' (и всех используемых в нём типов, состав всех енумов) строго соответствуют ожидаемому состоянию.

Т.е. получается:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    [Fact]
    public void DbSchemeStructureTest()
    {
        //
        var type = typeof(Database);
 
        //Ожидаемая структура (из JSON, например).
        var expectedTypeInfo = LoadExcpectedTypeStructure(type);
 
        //Разбор (через reflection) структуры типа 'Database' на всю глубину.
        var actualTypeInfo = ParseByReflection(type);
 
        //
        Assert.True(expectedTypeInfo.Equals(actualTypeInfo));
    }
Теперь получается, что если кто-то внесёт изменения в тип 'Database' (или любой используемый в нём тип), то второй тест не пройдёт. Нужно будет внести изменения в метод 'LoadExcpectedTypeStructure'. И где-то там надо будет написать очень заметный комментарий, что в случае внесения изменений в 'LoadExcpectedTypeStructure' нужно согласнованно доработать первый тест, а именно:
1. Дополнить метод 'PreapareTestDb' новыми сценариями.
2. Дописать в 'expectedDbStructure.Equals' логику сравнения для новых свойств/типов.

P.S.: вопрос - как сделать это правильно ? Потому как сейчас это выглядит слишком громоздко (в плане написания всех вспомогательных методов и подготовки тестовых данных). И не слишком надёжно, т.к. по сути оставляет шанс, что первый тест попросту забудут доработать под новые сценарии, т.к. он просто пройдёт, и его просто не заметят.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
02.06.2025, 21:16
Ответы с готовыми решениями:

Полиморфизм: вызов метода базового класса, переопределенного метода и нового метода
В базовом классе метод помечен как virtual. Насколько я понял из книги: override означает, что...

Юнит-тест для метода
Есть класс но сделать под него юнит тест не выходит если ты добрый человек помоги прошу ...

Unit-тест для void метода
Возник вопрос, как написать юнит тест для void метода, не принимающего ничего. using System;...

100
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
03.06.2025, 12:20  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Wolfdp Посмотреть сообщение
- делаем тестовую БД, в которой будут неправильные и правильные значения (т.е. максимально покрываем возможные варианты)
Так сейчас так и делается - тот самый метод 'PreapareTestDb' из самого первого примера. Его задача - подготовить тестовую БД ожидаемой структуры с полным покрытием всех возможных сценариев.

Цитата Сообщение от Wolfdp Посмотреть сообщение
В идеале стоит замокать весь connection
Не, один из смыслов этих тестов - проверить, что корректно написаны (и не поломаны кем-то) в т.ч. и все 'select * from information_schema.tables ...', которые собирают информацию о структуре БД. А корректность SQL может проверить только реальный сервер БД.

Цитата Сообщение от Wolfdp Посмотреть сообщение
Мок оооочень упрощает тестирование:
Да, но я так понимаю это именно для случаев, когда надо, скажем, протестировать какой-то сервис, который обращается к какому-то репозиторию/датасервису, и тогда можно не использовать реальный репозиторий/датасервис, а просто предоставить (через интерфейс) заглушку с предопределёнными для теста данными. Конкретно в данном случае для тестирования вышестоящего сервиса разницы не будет вообще никакой, но при этом не потребуется реальная БД.

У меня же тут надо тестировать именно SQL-запросы и интерпретацию их результатов, потому у меня вон тот вариант, как в Dapper-тестах.

Цитата Сообщение от Wolfdp Посмотреть сообщение
В прошлой теме один из форумчанинов писал что тесты в том числе показывают насколько хорошо продумана архитектура. Если плохо -- то тесты сложно написать. Ну вот -- по ходу есть проблемы в архитектуре.
Скорее всего. Но код сейчас простой и понятный, и сложно заставить себя усложнять его ради тестов ).
0
 Аватар для Andrey-MSK
3381 / 2267 / 388
Регистрация: 14.08.2018
Сообщений: 7,683
Записей в блоге: 4
03.06.2025, 12:26
Цитата Сообщение от kotelok Посмотреть сообщение
что корректно написаны (и не поломаны кем-то) в т.ч. и все 'select * from information_schema.tables ...'
Делаешь один раз в БД хранимку и всё, работать она будет всегда одинаково. Просто так в неё никто не полезет, а в методе ЯП можно навертеть, по неосторожности, много чего, особенно при рефакторинге.
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
03.06.2025, 13:14
Цитата Сообщение от kotelok Посмотреть сообщение
Не, один из смыслов этих тестов - проверить, что корректно написаны
Так не стоит делать. Нормальная ситуация, когда на один метод пишеться пять-десять отдельных тестов, а не один жирный, которые проверяет всё и вся. Я тоже по неопытности вначале пытался делать тест "поплотнее", но потом понял что с этим больше проблем, чем профита.

Вам нужно проверить что метод отработал и вернул нужные данные -- проверяйте только это и ничего больше.

Вам нужно проверить вызов select * from scheme? Пишем тест, проверит это и опять же -- ничего больше.

Замечу что ваше "не хочеться усложнять код" как раз и мешает легко проверить этот вызов. Так бы вы протестировали непосредственный класс взаимодействия с БД, без включения логики сравнения фактическое схемы и описанной в json (причём можно вынести в отдельный проект, чтобы остальные тесты были атомарными). А верхний DatabaseParser не имел бы представления с чем он там работает, главное чтобы правильно выполнял сравнение и вызов изменений. "Разделяй и властвуй" в программировании очень удачно работает.

Не по теме:

P.S. отдельно замечу что тоже не уловил задум этого json, по которому приводят БД к какому-либо виду. Обычно работают через версии и миграции. Проблема в том что "убрать индекс" ещё можно без последствий, а вот убрать колонку в таблице -- это будь-те добры сначала проверьте что она нигде не используется в качестве FK. Или вообще типичная ситуация -- добавить таблицу и заполнить её на основе десятка других таблиц. Код который будет всё это учитывать должен быть немаленьким.

На разработке мне понравился такой подход:
- создаются скрипты для чистого развёртывания проекта. Без них -- хрен найдёшь актуальную БД, особенно если разработка на потоке в нескольких ветках. Есть ситуации, когда заполнение данными очень проблемное (например они привязаны к стороннему облачному сервису), в этом случае приходится писать модуль импорта и экспорта данных.
- для актуального продакшенам в дальнейшем пишуться скрипты миграции.
- в качестве теста перед вливанием в мастер запускается сравнение БД развёрнутой с нуля, и БД полученной путём запуска скрипта миграции на бэкапе прошлой версии.

1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
03.06.2025, 13:37  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
Вам нужно проверить что метод отработал и вернул нужные данные -- проверяйте только это и ничего больше.
Вам нужно проверить вызов select * from scheme? Пишем тест, проверит это и опять же -- ничего больше.
Сейчас у библиотеки есть ровно один публичный метод, который принимает коннект, JSON и дальше делает всё.

При этом, где-то внутри того же класса парсера, есть приватные методы, которые содержат в себе в т.ч. весь SQL и интерпретацию его результатов, которые выполняют какие-то маленькие задачи типа:
C#
1
private static string EscapeName(string name) => $"[{name}]";
И если требуется закрыть это тестами, то получается надо рефакторить следующим образом:

1. Сделать сборку с тестами "дружественной" к тестируемой сборке. Тогда она сможет видеть все 'class Some' и 'static class Other' из этой сборки (т.е. для тестирования не придётся рефлексию использовать). При этом все реальные проекты, которые эту библиотеку используют, не получат доступа к внутренним деталям реализации.

2. Все простые приватные методы сделать публичными, но разместить их во внутренних классах, ну т.е. что-то типа:
C#
1
2
3
4
static class SqlServerHelpers
{
    public static string EscapeName(string name) => $"[{name}]";
}
Доступ к данным БД спрятать под абстракции типа:
C#
1
2
3
4
5
sealed class SqlServerColumnsProvider : IColumnsProvider
{
    //Тут сокрыт конкретный SQL-запрос.
    //И отсюда в каком-то виде возвращаются сырые данные.
}
В итоге для 'SqlServerColumnsProvider' (именно конкретной реализации под конкретный тип СУБД) тест будет выполняться поверх реальной БД (с пресетом данных для теста) и проверять, что вернулось ожидаемое количество в ожидаемом порядке и т.п., т.е. это будет именно тест SQL-запроса к БД.

А метод парсера, который разбирает список колонок из БД и на основании этого реализует какую-то логику, будет работать поверх абстрации 'IColumnsProvider', а потому при его тестировании можно будет использовать заглушку реализации 'IColumnsProvider', работающую не напрямую с БД, а предоставляющую тестовые данные из какой-то статичной коллекции.

Примерно такая суть?
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
03.06.2025, 19:53
По идеи "да", но читал бегло. То что некоторые классы интёрнал это грустно, особенно если ваш проект имеет цифровую подпись. Без неё просто указываем в асембли дружественные асембл-нейм (самих тестов, и вроде ещё мок либы, там прям в ошибке подскажет чего не хватает). С подписью там нужно строгие имена указывать или что-то в этом духе (я так особо и не разобрался).
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
03.06.2025, 20:17  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
То что некоторые классы интёрнал это грустно
А как ещё выкрутиться? Вот есть какой-то чисто внутренний функционал сборки, который наружу предоставлять не надо.

Но его надо тестировать. Я попробовал через рефлексию, но это как-то очень уж утомительно

Если описать класс как:
C#
1
2
sealed class SqlServerColumnsProvider : IColumnsProvider
{
Или как:
C#
1
2
3
4
static class SqlServerHelpers
{
    public static string EscapeName(string name) => $"[{name}]";
}
То в пределах сборки он всем доступен. Это не совсем удобно, конечно, что часть изнчально приватных методов становятся доступны всем другим классам этой сборки, но некритично. При этом снаружи такие классы не видны из других сборок. Но их можно сделать видимым для тестовой сборки через 'InternalsVisibleTo'. Вроде, это компромиссный вариант, который меньше всего неудобств создаёт.

Или ещё какие-то варианты есть, как тестировать внутренний функционал, не раскрывая его наружу?
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
03.06.2025, 21:22
Цитата Сообщение от kotelok Посмотреть сообщение
А как ещё выкрутиться? Вот есть какой-то чисто внутренний функционал сборки, который наружу предоставлять не надо.
Я имел в виду что придется малость повозиться, но к счастью только один раз при создании проекта. То что по имени можно будет достучаться -- по идеи не должно создавать проблем. Максимум который могу предположить, это если подразумевается обфускация внутреннего кода и тулза для этого может не дружить с этим атрибутом (чисто предположение, я бы как раз ожидал что проблем с этим не должно быть).

Я лично писал так же через InternalsVisibleTo, но скрывать внутрянку доводилось только на личных проектах для баловства. На продакшен обычно все и всё фигачат public без задней мысли
1
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
03.06.2025, 21:48
kotelok, не не не! Понимаю ваш энтузиазм в познании тестирования, но вас повело не туда...
Sealed - запечатанные классы тестируются особым образом, причем для этого заранее предусматриваются интерфейсы с теми же членами, что и запечатанный класс.
Создаются re-preventative объекты этих классов и они спокойно тестируются. Вложенная логика первичных original классов при этом не раскрывается.
А вообще, лучше через моки.

Добавлено через 1 минуту
Цитата Сообщение от kotelok Посмотреть сообщение
через 'InternalsVisibleTo'.
Это прям тяжелые случаи. Не ваш, явно.
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
03.06.2025, 21:52  [ТС]
Цитата Сообщение от wizard41 Посмотреть сообщение
Sealed
Я это просто на автомате написал, оно тут никакого значения не имеет.

Вопрос в том, что внутри сборки есть некий класс, который реализует часть внутренней логики и, соответственно, он не имеет модификатора 'publiс', не реализует никакие интерфейсы. И этот класс не будет виден из сборки с тестами, т.к. оно не 'public'. Но его надо протестировать.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
03.06.2025, 21:59
Если внутренний класс не виден снаружи, то он так и остается невидимым, даже для тестов. Если его члены/методы вызывают элементы класса-"матки", то ничего страшного..

Добавлено через 3 минуты
И вообще, классы внутри классов обычно и делают с тем расчетом, чтобы они были скрыты извне. Это абсолютно нормальный сценарий.
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
03.06.2025, 22:17  [ТС]
wizard41,
Тогда опять всё запуталось ).

Вот есть у меня библиотека. И в ней очень много сложной внутренней логики, размещённой в классах, которые за пределами сборки не видны (ибо они и не должны быть видны наружу). И весь внешний контрат этой библиотеки сводится к:
C#
1
2
3
4
public class Updater
{
    public void Apply(string json, IDbConnection conn);
}
Всё, больше оно ничего наружу не предоставляет.

Получается, надо писать тесты исключительно на уровне этого метода 'Apply', прогоняя через него сотни сложных вариаций входных данных и тестируя результаты работы через парсинг базы данных, указанной в 'conn'?

Судя по статьям, есть два холиварных подхода:
1. Тестируем только внешний контракт мега-запутанными комплексными тестами. В этом случае тесты усложняются и в разработке, и в поддержке. Но не надо лезть внутрь сборки.
2. Покрываем тестами вообще все детали внутренней реализации. В этом случае получаем огромное количество простых тестов, но для реализации такого подхода приходится немного поступаться инкапсуляцией.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
03.06.2025, 22:31
Цитата Сообщение от kotelok Посмотреть сообщение
поступаться инкапсуляцией
Чой то это?
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
03.06.2025, 23:06
.delete

Добавлено через 6 минут
Цитата Сообщение от wizard41 Посмотреть сообщение
Если внутренний класс не виден снаружи, то он так и остается невидимым, даже для тестов.
Либо вы не правильно поняли что делает InternalsVisibleTo, либо считаете что если internal, то нельзя даже на тесты шарить.

Если второе, то на мой взгляд это не правильно. То что внутренняя логика скрывается от конечного пользователя, не означает что её нельзя шарить для внутреннего использования. Зачастую скрывают для того чтобы пользователи не путались в россыпи классов и методов, а чётко следовали контракту.

ИМХО, для тестов расшарить internal через InternalsVisibleTo вполне нормальное решение.
2
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
03.06.2025, 23:12  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
Либо вы не правильно поняли что делает InternalsVisibleTo
Он делает класс, описанный как:
C#
1
2
3
class Some
{
}
Видимым для конкретной указанной сборки (ну т.е. в данном случае для сборки с тестами).

Собственно, я сейчас именно так и расшариваю все детали внутренней реализации для тестов.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
03.06.2025, 23:30
Wolfdp, эмм, я об общем принципе. Имея в виду уровень подготовки автора вопроса.
Лично я не стал бы манипулировать InternalsVisibleTo перед тем, кто только начинает вникать в тесты.

Цитата Сообщение от Wolfdp Посмотреть сообщение
считаете что если internal, то нельзя даже на тесты шарить.
Конечно, у каждого свой опыт в этом деле, но мне били по рукам за это. Больно. (образно, конечно).

Добавлено через 8 минут
Wolfdp, у меня есть класс FooClass и в нем публичный метод Foo, который, в свою очередь, взаимодействует с внутренними полями и скрытыми классами. Вы тестируете метод Foo. Вам не должно быть интересно каким образом он решает поставленную задачу: вам предоставлен только этот класс, экземпляр которого создает тест.
Это может быть вообще закрытая библиотека с некорым кол-вом публичных членов - для тестирования ее вам не нужны скрытые реализации..

Добавлено через 4 минуты
А если эти реализации создают несколько человек, то они должны быть открыты для тестирования на любой стороне. Прием с InternalsVisibleTo - это прям нечто... Про это знаю, но на практике не видел еще..
Похоже на такое: каждый скрывает от всех свое, но для тестов нате пожалуйста..
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
04.06.2025, 00:31
Цитата Сообщение от wizard41 Посмотреть сообщение
Похоже на такое: каждый скрывает от всех свое, но для тестов нате пожалуйста..
Тесты же пишет обычно тот же разработчик, что и внутренности либы. Не особо пониманию в чём тут проблема.

Грубо говоря либа с внутренним классом (дабы избежать статики, делаем через internal конструктор проброс интерфейса)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System.Runtime.CompilerServices;
 
[assembly: InternalsVisibleTo("Nya.ExampleInternalTest.UnitTest")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
 
public class PublicService
{
    private readonly IInternalService _internalService;
 
    public PublicService()
        : this(new InternalService())
    { }
    internal PublicService(IInternalService internalService)
    {
        _internalService = internalService;
    }
 
    public string CalculateAndFormat(int a, int b)
    { 
        var result = _internalService.Calc(a,b);
        return $"result = {result}";
    }
}
 
internal class InternalService : IInternalService
{
    public int Calc(int a, int b)
        => a + b;
}
 
internal interface IInternalService
{
    int Calc(int a, int b);
}
Тесты

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using Moq;
using Nya.ExampleInternalTest.Lib;
 
[TestClass]
public sealed class PublicServiceTests
{
 
    [DataRow(1, 2, "result = 0")]
    [TestMethod]
    public void TestCalculateAndFormat(int a, int b, string expected)
    {
        // Arrange
        var mockInternalService = new Mock<IInternalService>();
        mockInternalService.Setup(x => x.Calc(It.IsAny<int>(), It.IsAny<int>()))
            .Returns(0);
        var publicService = new PublicService(mockInternalService.Object);
 
        // Act
        var actual = publicService.CalculateAndFormat(a, b);
 
        // Assert
        Assert.AreEqual(expected, actual);
    }
}
 
[TestClass]
public sealed class InternalServiceTests
{
    [DataRow(1, 2, 3)]
    [TestMethod]
    public void TestCalculateAndFormat(int a, int b, int expected)
    {
        // Arrange
        var publicService = new InternalService();
 
        // Act
        var actual = publicService.Calc(a, b);
 
        // Assert
        Assert.AreEqual(expected, actual);
    }
}
Внешний проект не может достучаться до внетреностей

C#
1
2
3
4
5
6
7
using Nya.ExampleInternalTest.Lib;
 
var service = new PublicService();
//var internalService = new InternalService(); // not access
//var service2 = new PublicService(null); // not access
 
var result = service.CalculateAndFormat(-1, 5);
Таки хотелось бы понять в чём проблема...

Не по теме:

Цитата Сообщение от wizard41 Посмотреть сообщение
Конечно, у каждого свой опыт в этом деле, но мне били по рукам за это.
Обычно объясняют почему это плохо. Если просто бьют -- как-то странно.

Например когда я настрочил мега тест на всё и вся, мне сразу объяснили -- разбей, т.к. в твоём тесте чёрт ногу сломит. Не понятно что влияет на результат, а что нет.

Вложения
Тип файла: zip Nya.ExampleInternalTest.zip (6.1 Кб, 0 просмотров)
2
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
04.06.2025, 07:32  [ТС]
Цитата Сообщение от wizard41 Посмотреть сообщение
Это может быть вообще закрытая библиотека с некорым кол-вом публичных членов - для тестирования ее вам не нужны скрытые реализации..
А если у библиотеки всего один публичный метод и огромная внутренняя реализация с множеством классов, методов-расширений, просто статических вспомогательных методов? Мне, как разработчику, разве не надо всё это закрыть маленькими специализированными тестами, чтобы в случае каких-то исправлений в будущем, иметь возможность быстро отловить где именно и почему произошла ошибка? При этом перегружать внешний контракт библиотеки, выставляя наружу вообще всё - это, вроде, немного странно выглядит.

Цитата Сообщение от wizard41 Посмотреть сообщение
Прием с InternalsVisibleTo - это прям нечто... Про это знаю, но на практике не видел еще..
Вообще, вроде повсеместно используется. Я на этот вариант в паре статей изначально наткнулся. Потом на гитхабе посмотрел разные популярные проекты, там везде тестовые сборки прописаны в 'InternalsVisibleTo' основных библиотек - Dapper, Avalonia, .NET Runtime и т.п.:
Code
1
2
3
[assembly: InternalsVisibleTo("Dapper.Tests"
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTest"
[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection.Tests"
--
Ну т.е., например, как мне (именно как разработчику библиотеки) протестировать вот этот метод?
C#
1
2
3
4
5
6
7
static class StringHelpers
{
    public static string CamelCaseToSnakeCase(string str)
    {
        ..
    }
}
Сейчас просто добавил библиотеку с тестами в дружественные к тестируемой библиотеке. Пробовал через рефлексию ещё, но это совсем неудобно.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
04.06.2025, 12:18
kotelok, в целом можно сказать, что каждый пишет тесты для самого себя как пожелает. Тут нет каких=то четких правил, т.к. у каждого свой энвиронмент.
Что мешает, например, "вытащить" какой-то внутренний метод временно, протестировать, убедиться что он капец какой правильный и засунуть обратно внутрь чего-то? И больше про него не вспоминать..

Цитата Сообщение от kotelok Посмотреть сообщение
Пробовал через рефлексию ещё
Так тестируют обычно что-то недоступное для разработчика. Зачем применять рефлекс самому разрабу, который сам же все и пишет? ))
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
04.06.2025, 12:24  [ТС]
Цитата Сообщение от wizard41 Посмотреть сообщение
И больше про него не вспоминать..
Так вроде одна из задач теста именно в том, чтобы он обратил внимание на ошибку, если спустя год вдруг случится позыв что-то оптимизировать или как-то отрефакторить какой-то внутренний метод (причём, не обязательно у изначального разработчика).

Цитата Сообщение от wizard41 Посмотреть сообщение
Зачем применять рефлекс самому разрабу, который сам же все и пишет? ))
Не знаю. Просто один из вариантов, который упоминается в статьях. Позволяет целевую сборку вообще никак не подстраивать под систему тестирования (не надо ничего наружу выставлять, не надо дружественные сборки прописывать).
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
04.06.2025, 12:35
Цитата Сообщение от kotelok Посмотреть сообщение
если спустя год вдруг
Все верно. Так этот общий метод тест провалит, что приведет к его "разбору" на предмет что случилось. И хорошо, если это будет сам автор, а если это либа чья-то и нет исходников? Тогда эти тесты будут определять лишь вероятность перемещения этой либы в корзину..

Цитата Сообщение от kotelok Посмотреть сообщение
Просто один из вариантов
Ну вариантов на самом деле много разных, но стоит ли самому себе палки в колеса втыкать?

Добавлено через 1 минуту
И не уверен что Dapper является прям эталоном в тестировании, на который нужно равняться..
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
04.06.2025, 12:35

Unit тест для метода
имеется следующий метод public int Summ(string s) { return s.Split(new {','},...

Юнит-тест для асинхронного метода
Доброго всем времени суток! В теме &quot;Логирование при использовании многопоточности&quot; уважаемый...

Unit тест для метода
привет всем, есть следущий метод: private void CheckChanges() { if...

Вызов переменной метода A из метода В
Добрый день. Подскажите как происходит вызов Например даны два класс А и В, в каждом классе есть...

Вызов метода, ожидающего завершение другого метода
Имеется процедура Proc. Я её вызываю в Button. Только вот программа, не дожидаясь завершения...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Из невошедшего на форум (диалог с ИИ-гугла)
zorxor 29.07.2026
А вот, что интересно, сказал мне ИИ-гугла: Этот текст — эмоциональный пост пользователя под ником zorxor на интернет-форуме (вероятно, посвященном мистике, непознанному или альтернативной науке). . . .
Был праздник вчера, а я и не знал.
kumehtar 28.07.2026
27. 07. 2026г. Intel Core 2 Duo исполнилось 20 лет Новости компьютерного мира и их обсуждение (4) Салют, шампанское, овации! :drink:
Нейтральные знания, чистый код - бла-бла-бла-бла, на самом деле кликбейт и самореклама, плагиат, и вот почему
Hrethgir 27.07.2026
То-есть отклонение такой публикации говорит само за себя, и пусть только возьмут на вооружение после отклонения публикации - это будет чистейшим актом плагиата. Отклонял Хабр. Дословно, отклонённая. . .
тв 16 бой ии
anaschu 27.07.2026
Великий Перелом ИИ: Как уравнения ОДУ Radau дожали цензурные фильтры Алисы Фиксируем в мемофонде Теории Всего беспрецедентный факт в истории ИИ-зондирования. В затяжном многораундовом. . .
мв 15. непроверенное, возможно, глюк
anaschu 27.07.2026
НАУЧНО-АНАЛИТИЧЕСКИЙ ОТЧЕТ. РАЗДЕЛ 1. 1: «НАУКА» (РАСШИРЕННАЯ СТЕХИОМЕТРИЧЕСКАЯ И ГЕНЕТИЧЕСКАЯ ВЕРСИЯ)Тема: Теоретическое обоснование инвариантности 19-мерного тензорного ядра непрерывных ОДУ и. . .
Очистка реквизитов и табличных частей документа при копировании (вариант 2)
Maks 26.07.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРаботу", разработанного в КА2. Задача: Заменить алгоритм запрета копирования документов для сотрудников с ролью "Стажер",. . .
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru