Snapshooter adalah alat pengujian snapshot untuk .NET Core dan .NET Framework
Snapshooter adalah alat pengujian snapshot yang fleksibel untuk menyederhanakan validasi hasil dalam tes unit Anda di .net. Ini didasarkan pada gagasan pengujian snapshot Jest.
Untuk mendapatkan informasi lebih rinci tentang Snapshooter, buka dokumen Snapshooter
Untuk memulai, instal paket Snapshooter Xunit atau Nunit Nuget:
dotnet add package Snapshooter.Xunitdotnet add package Snapshooter.NUnitdotnet add package Snapshooter.MSTestMulai
Untuk menegaskan hasil tes Anda dengan snapshot di tes unit Anda, ikuti langkah -langkah berikut:
Masukkan Snapshot Assert Snapshot.Match(yourResultObject); ke dalam tes unit Anda.
Contoh:
/// <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 ) ;
} Pernyataan Snapshot.Match(person) membuat snapshot baru dari objek hasil Anda dan menyimpannya di folder __snapshots__ . Folder __snapshots__ selalu di sebelah file uji unit Anda yang dieksekusi.
Nama Snapshot: <UnitTestClassName>.<TestMethodName>.snap
Tinjau file snapshot baru Anda __snapshots__/<UnitTestClassName>.<TestMethodName>.snap .
Sekarang pernyataan Snapshot.Match(person) akan membuat lagi snapshot dari hasil tes Anda dan membandingkannya dengan snapshot yang Anda ulas di folder __snapshots__ . Folder __snapshots__ selalu di sebelah file uji unit Anda yang dieksekusi.
Jika objek hasil Anda telah berubah dan snapshot yang ada tidak cocok lagi, maka uji unit akan gagal. Pesan kesalahan uji unit akan menunjuk ke posisi ketidakcocokan yang tepat dalam snapshot.
Selain itu, di folder snapshot __snapshots__ subfolder dengan nama __mismatch__ akan dibuat. Di folder ini Anda dapat menemukan snapshot aktual yang tidak cocok dengan snapshot yang ada di folder __snapshots__ . Oleh karena itu dimungkinkan untuk membandingkan dua snapshot dengan alat banding teks.
Jika snapshot dalam folder yang tidak cocok __mismatch__ sudah benar, cukup pindahkan ke folder induk __snapshots__ (ganti yang sudah ada).
Baca selengkapnya
Sintaks kecocokan default untuk snapshot adalah:
Snapshot . Match ( person ) ;Namun, kami juga bisa menggunakan sintaks yang lancar:
person . MatchSnapshot ( ) ;Atau kita dapat menggunakan sintaks harus () FLUENTASSERTION:
person . Should ( ) . MatchSnapshot ( ) ;Untuk Nunit, kami akan mendukung Sintaks.
Assert . That ( person , Match . Snapshot ( ) ) ; Jika beberapa bidang dalam snapshot Anda harus diabaikan selama pernyataan snapshot, maka opsi abaikan berikut dapat digunakan:
[ 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" ) ) ;
}Bidang yang harus diabaikan akan ditempatkan melalui JSONPATH, oleh karena itu Anda sangat fleksibel dan Anda juga dapat mengabaikan bidang dari objek atau array anak.
Abaikan contoh:
// 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" ) ) ; Jika kita ingin mengabaikan semua bidang dengan nama tertentu, maka kita memiliki dua opsi:
Opsi 1: Gunakan opsi kecocokan abaikan 'IgnoreAllfields ()' dan tambahkan namanya.
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreAllFields ( "Id" ) ) ;Opsi 2: Gunakan opsi kecocokan abaikan default 'Ignorefields (**.)' Dengan sintaks JSONPath berikut **.
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreFields ( "**.Id" ) ) ;Jika beberapa bidang snapshot kami terlalu besar, misalnya bidang biner dengan banyak data, maka kami dapat menggunakan opsi hashfield. Opsi hashfield menciptakan hash dari nilai lapangan dan oleh karena itu setiap kali hanya hash yang dibandingkan. Jika ada perubahan dalam nilai bidang, maka kecocokan snapshot akan gagal.
[ Fact ]
public void ImageSnapshot_HashImageBinary ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestImage image = serviceClient . CreateMonaLisaImage ( ) ;
// assert
Snapshot . Match ( image , matchOptions => matchOptions . HashField ( "Data" ) ) ;
}Contoh snapshot dengan hash
{
"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= "
}Lapangan ke hash dapat ditempatkan melalui jsonpath atau melalui nama lapangan.
Contoh Lapangan Hash:
// 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" ) ) ;Terkadang ada bidang dalam snapshot, yang ingin Anda tegaskan secara terpisah terhadap nilai lain.
Misalnya, bidang ID dari 'orang' selalu baru dihasilkan dalam layanan, oleh karena itu Anda menerima dalam tes selalu seseorang dengan ID baru (GUID). Sekarang jika Anda ingin memeriksa bahwa ID bukanlah guid kosong, opsi Assert dapat digunakan.
/// <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" ) ) ) ) ;
}Bidang untuk menegaskan akan berlokasi melalui JsonPath, oleh karena itu Anda sangat fleksibel dan Anda juga dapat mengabaikan bidang dari objek anak atau array.
Menegaskan contoh:
// 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[*]" ) ) ) ) ;Fungsionalitas penegasan snapshooter tidak terbatas pada Xunit atau Nunit Asserts, itu juga dapat digunakan pernyataan fasih atau alat penegasan lainnya.
Semua pemeriksaan lapangan abaikan, iStype atau menegaskan dapat digabungkan.
[ 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" ) ) ) ) ;
} Saat menjalankan snapshooter tes dalam CI-Build, Anda mungkin ingin memastikan bahwa snapshot diperiksa dengan benar karena jika tidak, tes tanpa snapshot hanya akan membuat snapshot awal dan menjadi hijau.
Untuk gagal tes yang tanpa snapshot pada CI-Build Anda, Anda dapat mengatur perilaku snapshooter ke mode ketat dengan mengatur variabel lingkungan SNAPSHOOTER_STRICT_MODE on atau true .
Proyek ini telah mengadopsi Kode Etik yang ditentukan oleh Kontributor Perjanjian untuk mengklarifikasi perilaku yang diharapkan di komunitas kami. Untuk informasi lebih lanjut, lihat Kode Etik Life OSS Swiss.