Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Типы заглушек — это важная технология, предоставляемая платформой Microsoft Fakes, которая позволяет легко изолировать тестируемый компонент от других компонентов, на которые он полагается. Заглушка выступает в качестве небольшого фрагмента кода, заменяющего другой компонент во время тестирования. Ключевым преимуществом использования заглушек является возможность получать стабильные результаты, что облегчает написание тестов. Даже если другие компоненты еще не полностью функциональны, вы по-прежнему можете выполнять тесты с помощью заглушек.
Чтобы эффективно применять заглушки, рекомендуется разработать компонент таким образом, чтобы он в первую очередь зависел от интерфейсов, а не от конкретных классов от других частей приложения. Этот подход к проектированию способствует развязке и снижает вероятность того, что изменения в одной части потребуют изменений в другой. При тестировании этот шаблон проектирования позволяет заменить реализацию заглушки для реального компонента, обеспечивая эффективную изоляцию и точное тестирование целевого компонента.
Например, рассмотрим схему, которая иллюстрирует задействованные компоненты:
На этой схеме тестируемый компонент, StockAnalyzerкак правило, зависит от другого компонента RealStockFeed. Однако RealStockFeed создает проблему для тестирования, так как оно возвращает разные результаты при каждом вызове методов. Эта изменчивость затрудняет обеспечение согласованного и надежного StockAnalyzerтестирования.
Чтобы преодолеть это препятствие во время тестирования, мы можем принять практику внедрения зависимостей. Этот подход включает написание кода таким образом, чтобы он явно не упоминал классы в другом компоненте приложения. Вместо этого вы определяете интерфейс, который другой компонент и заглушка могут реализовать для тестирования.
Ниже приведен пример использования внедрения зависимостей в коде:
Ограничения заглушки
Ознакомьтесь со следующими ограничениями для заглушек.
Подписи методов с указателями не поддерживаются.
Запечатанные классы или статические методы не могут быть заглушены с использованием типов заглушек, так как они зависят от вызова виртуальных методов. В таких случаях используйте типы схимов, как описано в разделе "Использование шима" для изоляции приложения от других сборок для модульного тестирования
Создание заглушки: пошаговое руководство
Давайте начнем это упражнение с мотивирующим примером: одним из них, показанным на предыдущей схеме.
Создание библиотеки классов
Выполните следующие действия, чтобы создать библиотеку классов.
Откройте Visual Studio и создайте проект библиотеки классов .
Настройте атрибуты проекта:
- Установите имя проекта на StockAnalysis.
- Задайте для имени решения значение StubsTutorial.
- Установите целевую платформу проекта на .NET 8.0 или более позднюю версию.
Удалите файл по умолчанию Class1.cs.
Добавьте новый файл с именем IStockFeed.cs и скопируйте его в следующее определение интерфейса:
Добавьте еще один новый файл с именем StockAnalyzer.cs и скопируйте его в следующее определение класса:
Создание тестового проекта
Создайте тестовый проект для упражнения.
Щелкните правой кнопкой мыши решение и добавьте новый проект с именем MSTest Test Project.
Задайте для имени проекта значение TestProject.
Задайте целевую платформу проекта для .NET 8.0 или более поздней версии.
Добавить сборку Fakes
Добавьте сборку Fakes для проекта.
Добавьте ссылку проекта на
StockAnalyzer.
Добавьте сборку Fakes.
В обозревателе решений найдите ссылку на сборку:
Для старого проекта .NET Framework (не в стиле SDK) раскройте узел Ссылки в проекте модульного тестирования.
Для проекта в стиле SDK, предназначенного для .NET Framework, .NET Core или .NET 5.0 и более поздних версий, раскройте узел зависимостей, чтобы найти сборку, которую вы хотите замокировать в разделе сборки, проекты или пакеты.
Если вы работаете в Visual Basic, выберите "Показать все файлы " на панели инструментов обозревателя решений , чтобы просмотреть узел "Ссылки ".
Выберите сборку, содержащую определения классов, для которых требуется создать заглушки.
В контекстном меню выберите "Добавить фиктивную сборку".
Создание модульного теста
Теперь создайте модульный тест.
Измените файл по умолчанию UnitTest1.cs , чтобы добавить следующее
Test Methodопределение.[TestClass] class UnitTest1 { [TestMethod] public void TestContosoPrice() { // Arrange: int priceToReturn = 345; string companyCodeUsed = ""; var componentUnderTest = new StockAnalyzer(new StockAnalysis.Fakes.StubIStockFeed() { GetSharePriceString = (company) => { // Store the parameter value: companyCodeUsed = company; // Return the value prescribed by this test: return priceToReturn; } }); // Act: int actualResult = componentUnderTest.GetContosoPrice(); // Assert: // Verify the correct result in the usual way: Assert.AreEqual(priceToReturn, actualResult); // Verify that the component made the correct call: Assert.AreEqual("COOO", companyCodeUsed); } }Особый элемент магии — это класс
StubIStockFeed. Для каждого интерфейса в указанной сборке механизм Microsoft Fakes создает класс заглушки. Имя класса заглушки является производным от имени интерфейса с "Fakes.Stub" в качестве префикса, а имена типов параметров добавляются в конце.Заглушки также создаются для геттеров и сеттеров свойств, для событий и обобщённых методов. Дополнительные сведения см. в разделе Использование заглушек для изоляции частей приложения друг от друга для модульного тестирования.
Откройте обозреватель тестов и запустите тест.
Заглушки для различных типов элементов типа
Существуют заглушки для различных типов элементов типа.
Методы
В приведенном примере методы можно подменять путем присоединения делегата к экземпляру заглушечного класса. Имя типа заглушки является производным от имен метода и параметров. Например, рассмотрим следующий IStockFeed интерфейс и его метод GetSharePrice:
// IStockFeed.cs
interface IStockFeed
{
int GetSharePrice(string company);
}
Прикрепляем заглушку к GetSharePrice путём использования GetSharePriceString:
// unit test code
var componentUnderTest = new StockAnalyzer(new StockAnalysis.Fakes.StubIStockFeed()
{
GetSharePriceString = (company) =>
{
// Store the parameter value:
companyCodeUsed = company;
// Return the value prescribed by this test:
return priceToReturn;
}
});
Если вы не предоставляете заглушку для метода, Fakes создает функцию, которая возвращает default value тип возвращаемого значения. Для чисел значение по умолчанию равно 0. По умолчанию для типов классов: null язык C# или Nothing язык Visual Basic.
Свойства
Методы получения свойств и методы задания предоставляются в виде отдельных делегатов и могут быть помечены по отдельности. Например, рассмотрим Value свойство IStockFeedWithProperty:
interface IStockFeedWithProperty
{
int Value { get; set; }
}
Чтобы заглушить геттер и сеттер Value и создать автоматическое свойство, можно использовать следующий код:
// unit test code
int i = 5;
var stub = new StubIStockFeedWithProperty();
stub.ValueGet = () => i;
stub.ValueSet = (value) => i = value;
Если вы не предоставляете методы заглушки для метода задания или получения свойства, Fakes создает заглушку, которая сохраняет значения, что делает свойство заглушки поведением простой переменной.
Events
События предоставляются как поля делегатов, что позволяет любому заглушенному событию быть вызванным через простое обращение к соответствующему полю. Рассмотрим следующий интерфейс для создания заглушки:
interface IStockFeedWithEvents
{
event EventHandler Changed;
}
Чтобы инициировать событие Changed, вызовите поддерживающий делегат:
// unit test code
var withEvents = new StubIStockFeedWithEvents();
// raising Changed
withEvents.ChangedEvent(withEvents, EventArgs.Empty);
Универсальные методы
Универсальные методы можно заглушить, предоставив делегат для каждого требуемого экземпляра метода. Например, учитывая следующий интерфейс с универсальным методом:
interface IGenericMethod
{
T GetValue<T>();
}
Вы можете заглушить инициализацию GetValue<int> следующим образом:
[TestMethod]
public void TestGetValue()
{
var stub = new StubIGenericMethod();
stub.GetValueOf1<int>(() => 5);
IGenericMethod target = stub;
Assert.AreEqual(5, target.GetValue<int>());
}
Если код вызывает GetValue<T> с любой другой реализацией, заглушка выполняет своё поведение.
Заглушки виртуальных классов
В предыдущих примерах заглушки были сгенерированы из интерфейсов. Однако вы также можете создавать заглушки из класса с виртуальными или абстрактными элементами. Рассмотрим пример.
// Base class in application under test
public abstract class MyClass
{
public abstract void DoAbstract(string x);
public virtual int DoVirtual(int n)
{
return n + 42;
}
public int DoConcrete()
{
return 1;
}
}
В заглушке, созданной из этого класса, вы можете задать методы делегата для DoAbstract() и DoVirtual(), но не для DoConcrete().
// unit test
var stub = new Fakes.MyClass();
stub.DoAbstractString = (x) => { Assert.IsTrue(x>0); };
stub.DoVirtualInt32 = (n) => 10 ;
Если вы не предоставляете делегат для виртуального метода, Fakes может предоставить поведение по умолчанию или вызвать метод в базовом классе. Чтобы вызвать базовый метод, задайте CallBase свойство:
// unit test code
var stub = new Fakes.MyClass();
stub.CallBase = false;
// No delegate set - default delegate:
Assert.AreEqual(0, stub.DoVirtual(1));
stub.CallBase = true;
// No delegate set - calls the base:
Assert.AreEqual(43,stub.DoVirtual(1));
Изменение поведения заглушек по умолчанию
Каждый тип заглушки, созданный, содержит экземпляр интерфейса IStubBehavior через свойство IStub.InstanceBehavior. Это поведение вызывается всякий раз, когда клиент вызывает члена без присоединенного пользовательского делегата. Если поведение не задано, он использует экземпляр, возвращаемый свойством StubsBehaviors.Current . По умолчанию это свойство возвращает поведение, вызывающее NotImplementedException исключение.
В любой момент можно изменить поведение, установив свойство InstanceBehavior для любого экземпляра заглушки. Например, следующий фрагмент кода изменяет поведение так, чтобы заглушка либо ничего не делает, либо возвращает значение по умолчанию возвращаемого типа default(T):
// unit test code
var stub = new StockAnalysis.Fakes.StubIStockFeed();
// return default(T) or do nothing
stub.InstanceBehavior = StubsBehaviors.DefaultValue;
Поведение также можно изменить глобально для всех объектов заглушки, в которых поведение не задано свойством StubsBehaviors.Current :
// Change default behavior for all stub instances where the behavior has not been set.
StubBehaviors.Current = BehavedBehaviors.DefaultValue;