Snapshooter - это инструмент для тестирования снимка для .NET Core и .NET Framework
Snapshooter - это гибкий инструмент тестирования снимка для упрощения проверки результатов в ваших модульных тестах в .net. Он основан на идее тестирования шутка.
Чтобы получить более подробную информацию о снимке, перейдите к документам по снимкам.
Чтобы начать, установите пакет Snapshooter SduNit или NUNIT NUGET:
dotnet add package Snapshooter.Xunitdotnet add package Snapshooter.NUnitdotnet add package Snapshooter.MSTestНачните
Чтобы утвердить результаты теста с помощью снимков в ваших модульных тестах, выполните следующие шаги:
Вставьте Snapshot Assert Snapshot.Match(yourResultObject); в ваш модульный тест.
Пример:
/// <summary>
/// Tests if the new created person is valid.
/// </summary>
[ Fact ]
public void CreatePersonSnapshotTest ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestPerson person = serviceClient . CreatePerson (
Guid . Parse ( "2292F21C-8501-4771-A070-C79C7C7EF451" ) , "David" , "Mustermann" ) ;
// assert
Snapshot . Match ( person ) ;
} Заявление Snapshot.Match(person) создает новый снимок вашего объекта результата и хранит его в папке __snapshots__ . Папка __snapshots__ всегда рядом с выполненным файлом тестирования модуля.
Имя снижения: <UnitTestClassName>.<TestMethodName>.snap
Просмотрите свой новый файл снимков __snapshots__/<UnitTestClassName>.<TestMethodName>.snap .
Теперь оператор Snapshot.Match(person) снова создаст снимок вашего результата теста и сравнит его с рецензированным снимком в папке __snapshots__ . Папка __snapshots__ всегда рядом с выполненным файлом тестирования модуля.
Если ваш объект результата изменился, и существующий снимок больше не соответствует, то модульный тест потерпит неудачу. Сообщение об ошибке модульного теста будет указывать на точную несоответствующую позицию в снимке.
Кроме того, в папке снимка __snapshots__ будет создана подпапалка с именем __mismatch__ . В этой папке вы можете найти фактический снимок, который не соответствует существующему моментальному снимку в папке __snapshots__ . Поэтому можно сравнить два снимка с инструментом сравнения текста.
Если снимок в минимальной папке __mismatch__ является правильным, просто переместите его в родительскую папку __snapshots__ (переопределяйте существующую).
Читать далее
Синтаксис совпадения по умолчанию для снимков:
Snapshot . Match ( person ) ;Тем не менее, мы также могли бы использовать синтаксис Fluent:
person . MatchSnapshot ( ) ;Или мы можем использовать синтаксис FluentArsertion () Syntax:
person . Should ( ) . MatchSnapshot ( ) ;Для NUNIT мы будем поддерживать ASSERT.HT SYNTAX (скоро):
Assert . That ( person , Match . Snapshot ( ) ) ; Если некоторые поля в вашем снимке должны быть проигнорированы во время утверждения снимка, то можно использовать следующие параметры игнорирования:
[ Fact ]
public void CreatePersonSnapshot_IgnoreId ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestPerson person = serviceClient . CreatePerson ( "Hans" , "Muster" ) ;
// assert
Snapshot . Match < Person > ( testPerson , matchOptions => matchOptions . IgnoreField ( "Size" ) ) ;
}Поля, которые следует игнорировать, будут расположены через jsonpath, поэтому вы очень гибкие, и вы также можете игнорировать поля от дочерних объектов или массивов.
Игнорировать примеры:
// Ignores the field 'StreetNumber' of the child node 'Address' of the person
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreField ( "Address.StreetNumber" ) ) ;
// Ignores the field 'Name' of the child node 'Country' of the child node 'Address' of the person
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreField ( "Address.Country.Name" ) ) ;
// Ignores the field 'Id' of the first person in the 'Relatives' array of the person
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreField ( "Relatives[0].Id" ) ) ;
// Ignores the field 'Name' of all 'Children' nodes of the person
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreField ( "Children[*].Name" ) ) ;
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreField ( "**.Id" ) ) ; Если мы хотим игнорировать все поля с определенным именем, у нас есть два варианта:
Вариант 1: Используйте параметр «Игнорировать совпадение» «Игнорядочный фон ()» и добавьте имя.
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreAllFields ( "Id" ) ) ;Вариант 2: Используйте параметр «Игнорировать матч» «Игнорировать» (**.) 'С следующим синтаксисом jsonpath **.
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreFields ( "**.Id" ) ) ;Если некоторые поля нашего снимка слишком велики, например, двоичное поле с большим количеством данных, то мы можем использовать опцию хэш -поля. Вариант хэшфилда создает хэш значения поля, и поэтому каждый раз сравнивается только хеш. Если в значении поля произойдет изменение, то совпадение снимка потерпит неудачу.
[ Fact ]
public void ImageSnapshot_HashImageBinary ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestImage image = serviceClient . CreateMonaLisaImage ( ) ;
// assert
Snapshot . Match ( image , matchOptions => matchOptions . HashField ( "Data" ) ) ;
}Пример снимка с хэшем
{
"Id" : 3450987 ,
"OwnerId" : " 0680faef-6e89-4d52-bad8-291053c66696 " ,
"Name" : " Mona Lisa " ,
"CreationDate" : " 2020-11-10T21:23:09.036+01:00 " ,
"Price" : 951868484.345 ,
"Data" : " m+sQR9KG9WpgYoQiRASPkt9FLJOLsjK86UuiXKVRzas= "
}Поле (ы) в хэш может быть расположено через jsonpath или через имя поля.
Хэш -примеры:
// Hash the field 'Data' of the child node 'Thumbnail' of the person
Snapshot . Match < Person > ( person , matchOptions => matchOptions . HashField ( "Thumbnail.Data" ) ) ;
// Hash the field 'Data' of the first thumbnail in the 'Thumbnails' array of the image
Snapshot . Match < Person > ( person , matchOptions => matchOptions . HashField ( "Thumbnails[0].Data" ) ) ;
// Ignores the field 'Data' of all 'Thumbnails' nodes of the image
Snapshot . Match < Person > ( person , matchOptions => matchOptions . HashField ( "Thumbnails[*].Data" ) ) ;
// Ignores all fields with name 'Data'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . HashField ( "**.Data" ) ) ;Иногда в снимке есть поля, которые вы хотите утверждать отдельно против другого значения.
Например, полевое поле «человека» всегда вновь сгенерировано в службе, поэтому вы получаете в тесте всегда человека с новым идентификатором (GUID). Теперь, если вы хотите проверить, что идентификатор не является пустым гидом, можно использовать опцию Assert .
/// <summary>
/// Tests if the new created person is valid and the person id is not empty.
/// </summary>
[ Fact ]
public void CreatePersonSnapshot_AssertId ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestPerson person = serviceClient . CreatePerson ( "Hans" , "Muster" ) ; // --> id is created within the service
// assert
Snapshot . Match < Person > ( testPerson , matchOption => matchOption . Assert (
fieldOption => Assert . NotEqual ( Guid . Empty , fieldOption . Field < Guid > ( "Id" ) ) ) ) ;
}Поля для утверждения будут расположены через jsonpath, поэтому вы очень гибкие, и вы также можете игнорировать поля от дочерних объектов или массивов.
Утверждайте примеры:
// Assert the field 'Street' of the 'Address' of the person
Snapshot . Match < Person > ( person , matchOption => matchOption . Assert (
fieldOption => Assert . Equal ( 15 , fieldOption . Field < int > ( "Address.StreetNumber" ) ) ) ) ;
// Asserts the field 'Code' of the field 'Country' of the 'Address' of the person
Snapshot . Match < Person > ( person , matchOption => matchOption . Assert (
fieldOption => Assert . Equal ( "De" , fieldOption . Field < CountryCode > ( "Address.Country.Code" ) ) ) ) ;
// Asserts the fist 'Id' field of the 'Relatives' array of the person
Snapshot . Match < Person > ( person , > matchOption . Assert (
fieldOption => Assert . NotNull ( fieldOption . Field < string > ( "Relatives[0].Id" ) ) ) ) ;
// Asserts every 'Id' field of all the 'Relatives' of the person
Snapshot . Match < Person > ( person , > matchOption . Assert (
fieldOption => Assert . NotNull ( fieldOption . Fields < string > ( "Relatives[*].Id" ) ) ) ) ;
// Asserts 'Relatives' array is not empty
Snapshot . Match < Person > ( person , > matchOption . Assert (
fieldOption => Assert . NotNull ( fieldOption . Fields < TestPerson > ( "Relatives[*]" ) ) ) ) ;Функциональность Assert Snapshooter не ограничивается утверждениями XUNIT или NUNIT, его также можно использовать Fluent утверждения или другой инструмент Assert.
Все проверки поля игнорирования, ISTYPE или Assert могут быть объединены.
[ Fact ]
public void Match_ConcatenateFieldChecksTest_SuccessfulMatch ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestPerson person = serviceClient . CreatePerson ( "Hans" , "Muster" ) ;
// act & assert
Snapshot . Match < TestPerson > ( testPerson , matchOption => matchOption
. Assert ( option => Assert . NotEqual ( Guid . Empty , option . Field < Guid > ( "Id" ) ) )
. IgnoreField < DateTime > ( "CreationDate" )
. Assert ( option => Assert . Equal ( - 58 , option . Field < int > ( "Address.StreetNumber" ) ) )
. Assert ( option => testChild . Should ( ) . BeEquivalentTo ( option . Field < TestChild > ( "Children[3]" ) ) )
. IgnoreField < TestCountry > ( "Address.Country" )
. Assert ( option => Assert . Null ( option . Field < TestCountry > ( "Relatives[0].Address.Plz" ) ) ) ) ;
} При запуске тестов на снимках в CI-Build вы можете убедиться, что снимки были правильно зарегистрированы, поскольку тестирование в противном случае без моментального снимка просто создаст первоначальный снимок и станет зеленым.
Чтобы провалить тесты, которые не имеют снижения на вашей Ci-Build, вы можете установить поведение снимка для строгого режима, установив переменную среды SNAPSHOOTER_STRICT_MODE on или true .
Этот проект принял Кодекс поведения, определяемый Заветом участника, чтобы прояснить ожидаемое поведение в нашем сообществе. Для получения дополнительной информации см. Швейцарский кодекс поведения OSS.