PieceofScript adalah bahasa sederhana untuk menulis skrip untuk pengujian otomatis HTTP JSON API.
PieceofScript memungkinkan Anda untuk:
- menggambarkan metode API dalam format YAML, dengan nama metode dalam bahasa yang hampir alami, yang nyaman untuk membaca tes
- cukup fleksibel untuk menggambarkan model dalam format YAML dan menghasilkan data acak dari mereka
- tulis skrip panggilan API kompleks dalam bahasa yang mudah dibaca dengan sintaksis sederhana
- dapatkan hasil pengujian dalam format JUnit dan HTML
Saya menulis "sepeda" ini karena antarmuka SoapUI membuat saya jatuh. Saya ingin secara sederhana dan jelas menggambarkan tes dalam editor teks tanpa GUI khusus. Selain itu, git tidak mencerna file xml besar yang dikeluarkan oleh SoapUI, sehingga sulit untuk melakukan tes untuk tugas tertentu di cabang yang sama di mana tugas itu sendiri dilakukan. Antarmuka Postman jauh lebih baik, tetapi ketika berkembang, dibutuhkan banyak waktu untuk menulis / memodifikasi permintaan di sana dan mengulanginya dalam urutan yang benar. Saya ingin mengotomatiskannya. Saya juga mempelajari alat pengujian lain, masing-masing memiliki "
cacat fatal ", jadi pada saat
sindrom NIH saya membuka IDE.
Inilah yang terjadi.

Penerjemah ditulis dalam PHP dan merupakan arsip phar, ia membutuhkan versi PHP 7.2, meskipun mungkin juga berfungsi pada 7.1. Kode sumber dan dokumentasi
https://github.com/maximw/PieceofScript . Dokumentasi dalam pengembangan. Ternyata, ini adalah bagian yang paling sulit dan melelahkan.
Proyek pengujian, struktur dan peluncurannyaSkrip ujiMetode Uji APIPanggilan Metode APIPembuatan model dan data ujiFungsi bawaanUji kasusVariabel dan CakupanJenis dan OperasiMenyimpan data di antara prosesKeluaran ke stdout dan laporanContoh - kata yang cukup, tunjukkan kodenya!
Komentar dan rencana untuk masa depan, jika adaProyek pengujian, struktur dan peluncurannya
Proyek ini adalah direktori dengan satu set file skrip, file deskripsi metode API dan generator data uji.
Dalam versi minimal, proyeknya terlihat seperti ini:
./tests endpoints.yaml - API generators.yaml - start.pos -
File startup adalah skrip tempat proses pengujian dimulai. Sudah diatur saat startup:
pos.phar run ./start.pos --junit=junit_report.xml -vvv --config=config.yaml
Semua jalur relatif dibaca dari direktori kerja yang berisi file mulai.
File konfigurasi dapat ditentukan pada baris perintah dengan opsi
--config atau meletakkan
config.yaml di direktori kerja. Konfigurasi ini opsional, Anda harus naik ke sana sesuai kebutuhan.
Lebih lanjut tentang konfigurasi .
Skrip uji
Untuk saya sendiri, saya memutuskan untuk menulis skrip dalam file dengan ekstensi .pos, sehingga Anda dapat membuat pengaturan penyorotan kode di IDE dengan ekstensi ekstensi. Tetapi penerjemah benar-benar tidak peduli dengan ekstensi.
Berikut ini adalah contoh skrip sederhana untuk forum imajiner di mana pengujian membuat dan membaca posting oleh pengguna yang berbeda dilakukan.
require "./globals.pos"
Ya, itu tidak terlihat sangat baik tanpa lampu latar.
Setiap baris skrip dimulai dengan operator, atau panggilan ke metode API. Jika tiba-tiba nama metode API dimulai dengan kata yang cocok dengan salah satu operator, Anda dapat menggunakan simbol "
> ":
>Include $user to group $userGroup
Operator tidak peka huruf besar-kecil. menegaskan, ASSERT atau aSsErT (tetapi mengapa menulis seperti itu?) akan bekerja.
Setiap pernyataan atau panggilan metode API harus berada di jalur terpisah. Tetapi pembungkus baris juga dimungkinkan jika karakter terakhir dari string adalah
\ (halo, Python).
Detail tidak menarik tentang jeda baris dan indentasiJika pembungkus baris digunakan dalam komentar, baris berikutnya juga akan dianggap sebagai bagian dari komentar. Ketika membungkus garis di dalam blok (
testcase ,
jika ,
sementara ,
foreach ), penting untuk
indentasi sehingga baris berikutnya jatuh ke blok yang sama.
var $n = 20 var $i = 2 var $fib1 = 1; \ $fib2 = 1 while $i <= $n var $fib_sum = \ $fib2 + $fib1 print toString($i) + " :" + \ toString($fib_sum) var $fib1 = $fib2 var $fib2 = $fib_sum var $i = $i + 1
Saat mengeksekusi pernyataan blok (
testcase ,
if ,
while ,
foreach ), sebuah blok ditentukan oleh lekukan garisnya. Lekukan dihitung sebagai jumlah spasi putih di awal baris. Spasi dan tab dihitung sebagai satu karakter, tetapi tab biasanya ditampilkan dalam editor sebagai beberapa spasi. Oleh karena itu, untuk menghindari kebingungan, lebih baik menggunakan tab atau spasi, tetapi tidak semuanya.
Daftar lengkap operator
memerlukan fileName - lampirkan file ke tempat operator dipanggil. File yang dilampirkan akan segera mulai dari baris pertama. Setelah selesai, penerjemah kembali ke baris berikutnya dari file sumber. Jika file yang diminta tidak dapat dibaca, kesalahan akan dihasilkan. Jalur relatif dihitung dari direktori kerja.
termasuk fileMask - mirip dengan yang dibutuhkan, tetapi jika file yang diminta tidak dapat dibaca, tidak akan ada kesalahan. Ini nyaman, misalnya, untuk membuat pengaturan untuk berbagai lingkungan pengujian. Selain itu, include dapat menghubungkan semua file dengan mask sekaligus. Jadi, misalnya, Anda dapat mengunduh seluruh direktori file yang berisi kasus uji. Tetapi pada saat yang sama, urutan pengunduhan file tidak dijamin.
var $ variable1 = expression1 ; $ variable2 = expression2 ; ...; $ variableN = expressionN - tetapkan nilai ke variabel. Jika variabel belum ada, itu akan dibuat dalam konteks saat ini.
biarkan $ variable1 = expression1 ; $ variable2 = expression2 ; ...; $ variableN = expressionN - tetapkan nilai ke variabel. Jika variabel tidak dalam konteks saat ini, akan ada upaya untuk membuat atau memodifikasi variabel dalam konteks global.
const $ const1 = expression1 ; $ const2 = expression2 ; ...; $ constN = expressionN - tetapkan nilai konstanta dalam konteks saat ini. Perbedaan antara konstanta dan variabel hanya bahwa mereka tidak dapat diubah, ketika Anda mencoba untuk menetapkan nilai ke konstanta, peringatan akan dikeluarkan setelah deklarasi. Jika sudah ada variabel dengan nama yang sama, kesalahan akan dihasilkan ketika mencoba mendeklarasikannya sebagai konstanta. Jika tidak, segala sesuatu yang benar untuk variabel juga berlaku untuk konstanta.
impor $ variabel1 ; $ variable2 ; ...; $ variableN - menyalin variabel dari global ke konteks saat ini. Mungkin bermanfaat jika Anda perlu beroperasi pada nilai variabel global, tetapi tidak mengubahnya.
testcase testCaseName - mengumumkan kasus uji, yang kemudian dapat disebut sebagai unit dengan pernyataan
run .
Baca lebih lanjut tentang test case di artikel selanjutnya .
menegaskan pernyataan - periksa apakah
ungkapan itu
benar , jika tidak cetak laporan tentang pengujian yang gagal.
ekspresi harus sama dengan
menyatakan , hanya jika tes gagal, test case saat ini akan dihentikan. Dan di luar konteks test case, skrip akan dihentikan sama sekali. Ini dapat digunakan jika ada kesalahan yang tertangkap ketika pemeriksaan lebih lanjut tidak masuk akal.
jalankan testCaseName - jalankan test case yang ditentukan untuk dieksekusi.
berjalan tanpa menentukan nama kasus uji akan memulai semua kasus uji yang dinyatakan yang tidak memerlukan argumen dalam urutan deklarasi mereka.
while expression - sebuah loop, sementara
ekspresi benar, mengeksekusi pernyataan dengan garis indentasi lebih dari
sementara .
foreach $ array ; $ element - loop melalui array, loop body dieksekusi untuk setiap elemen berikutnya dari array. Dimungkinkan juga untuk mendapatkan kunci
foreach $ array ; $ key ; $ element . Variabel
$ key dan
$ element dibuat / ditimpa dalam konteks saat ini.
if ekspresi - jika
ekspresi benar, jalankan pernyataan dengan garis indentasi lebih dari
jikaekspresi cetak1 ; Ekspresi2 ; ... EkspresiN - mencetak nilai
ekspresiM ke stdout. Itu dapat digunakan untuk debugging, ia hanya bekerja dengan tingkat "talkativeness"
--verbosity = 1 atau
-v dan lebih banyak.
ekspresi tidur - jeda untuk nomor yang diberikan, opsional bilangan bulat, detik. Terkadang Anda perlu memberi waktu istirahat pada API yang diuji.
jeda ekspresi - tidak dalam mode interaktif (opsi baris perintah
-n ) mirip dengan
sleep .
Ekspresi adalah opsional, dalam hal ini tidak akan ada jeda. Dan dalam mode interaktif, jeda sebelum menekan Enter.
batalkan - akhiri pengujian. Penerjemah selesai bekerja, membuat laporan.
Metode Uji API
Ini sebenarnya yang perlu Anda uji - panggil dengan parameter tertentu dan periksa apakah jawabannya memenuhi harapan.
Metode API dijelaskan dalam format YAML. Secara default, deskripsi harus di file
endpoints.yaml dari direktori saat ini dan / atau di file
* .yaml di subdirektori
./endpoints . Sebelum pengujian, penerjemah akan mencoba membaca semua file ini sekaligus.
Contoh struktur
endpoints.yaml :
Auth $user: method: "POST" url: $domain + "/login" headers: Content-Type: "application/json" format: "json" data: login: $user.login password: $user.password after: - assert $response.code == 200 - let $user.auth_token = $response.body.auth_token Create post $post by $user: method: "POST" url: $domain + "/posts" format: "json" data: $post headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert $response.code == 201 Read post $postId by $user: method: "GET" url: $domain + "/posts/" + $postId headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert ($response.code == 200) || ($response.code == 404) Create comment $comment on $post by $user: method: "POST" url: $domain + "/comments/create/" + $post.id format: "json" data: $comment headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert $response.code == 201
Nama metode API (tingkat atas dari struktur YAML) yang dapat dipanggil adalah string dalam format yang hampir sewenang-wenang.
Argumen dapat ditentukan di mana saja dalam nama. Mereka harus dipisahkan oleh spasi dari sisa kata-kata. Sebagai contoh,
$ comment ,
$ post dan
$ user dalam metode terakhir.
Juga, di mana saja dalam nama Anda dapat menentukan nilai metode opsional dalam kurung keriting ganda.
Get comments of $post {{$page=1; $perPage=$defaultGlobalPageSize}}: method: "GET" url: $domain + "/comments/" + $post.id query: page: $page per_page: $perPage headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert $response.code == 200
Dalam ekspresi yang menentukan nilai opsional, variabel konteks global tersedia.
Nilai opsional dapat berguna sehingga Anda tidak menentukannya setiap kali Anda memanggil metode API. Jika ukuran halaman perlu diubah hanya di satu tempat, mengapa menunjukkannya di semua tempat lain? Contoh panggilan ke metode ini:
Get comments of $newPost // $page $perPage Get comments of $newPost {{$page=$currentPage+1}} Get comments of {$newPost} {{$perPage=10;$page=100}}
Sisa variabel yang digunakan (
$ domain pada contoh di atas) akan diambil dari konteks global. Saya akan memberi tahu Anda lebih banyak
tentang konteks nanti.
Menurut saya nyaman untuk memberikan metode API nama yang dapat dibaca manusia dalam bahasa alami, maka skrip uji lebih mudah dibaca. Nama tidak peka huruf besar kecil, mis., Metode
$ Pengguna Auth dapat disebut sebagai
$ Pengguna auth dan sebagai
Pengguna $ AUTH . Namun, nama variabel peka huruf besar-kecil, lebih lanjut
tentang variabel di bawah ini.
Catatan penting. Format YAML memungkinkan Anda untuk tidak menyertakan string dalam tanda kutip. Tetapi untuk penerjemah, string tanpa tanda kutip adalah ekspresi yang perlu dievaluasi. Misalnya, mendeklarasikan
url: http://example.com/login
akan menghasilkan kesalahan sintaks selama eksekusi. Karenanya, itu akan benar:
url: "http://example.com/login"
atau
url: "http://"+$domain+"/login"
Metode Deskripsi Bidang API
metode - metode HTTP yang diperlukan
url - URL yang sebenarnya, diperlukan
header - daftar header HTTP, opsional
cookies - daftar cookie opsional
auth - data untuk otentikasi HTTP, opsional
auth: login: $login password: $password type: "basic"
kueri - daftar parameter URL, opsional
format - salah satu nilai:
- tidak ada - permintaan tidak memiliki badan
- json - kirim ke JSON
- raw - kirim string "apa adanya"
- form - dalam format application / x-www-form-urlencoded
- multipart - dalam format multipart / formulir-data
Opsional,
tidak ada yang default
data - badan permintaan, akan dikirim dalam format yang ditentukan dalam
format , opsional
File yang ditentukan dalam bidang
file harus dapat dibaca. Jika URL ditentukan, maka
allow_url_fopen harus diaktifkan di php.ini
sebelum - pernyataan yang akan dieksekusi sebelum permintaan HTTP, opsional
setelah - pernyataan yang akan dieksekusi setelah permintaan HTTP, opsional
Gagasan blok
sebelum dan
sesudah dalam melakukan pemeriksaan atau pemrosesan data apa pun yang diperlukan setiap kali sebelum atau setelah menjalankan permintaan HTTP ditentukan tidak begitu banyak dengan menguji kebutuhan seperti oleh logika bisnis. Misalnya, menyalin token otorisasi yang dikeluarkan ke bidang struktur $ user untuk memanggil semua metode API berikutnya atas nama pengguna ini. Atau untuk memeriksa status HTTP dari respons, agar tidak memeriksanya setiap kali setelah panggilan dalam skrip.
Panggilan Metode API
Untuk memanggil metode API dalam skrip, Anda perlu menentukan nama dan parameternya, jika perlu. Berikut adalah contoh memanggil metode API terakhir dari deskripsi di atas:
Create comment $comments.1 on {$newPost} by {$postAuthor}
Jika parameter terlampir dalam kurung keriting, itu akan diteruskan oleh nilai - dengan cara ini Anda bisa melewatkan ekspresi apa pun. Jika Anda menentukan parameter tanpa kurung keriting, itu akan diteruskan dengan referensi - itu hanya bisa berupa variabel dan akses statis ke elemen array (melalui periode, tetapi tidak melalui kurung []).
Create comment {$comments[$i]} on $posts.0 by $users.1 Read post {123} by $user Get comments of $users.1.id {{$page = 2}}
Setiap kali metode API dipanggil dalam konteks panggilan itu sendiri (dalam daftar pernyataan
sebelum dan
sesudah ) dan dalam konteks di mana ia dipanggil, variabel
$ request dan
$ response dibuat . Ini adalah nama yang dilindungi undang-undang, saya tidak menyarankan menggunakannya untuk tujuan lain.
$ request tersedia di blok
sebelum dan
sesudah , dan
$ response hanya
setelah , di
sebelum nilainya menjadi
Null . Dalam konteks panggilan, variabel-variabel ini tersedia hingga metode panggilan API berikutnya, di mana mereka akan diinisialisasi ulang.
$ Struktur permintaan
$ request.method - String - Metode HTTP
$ request.url - String - URL yang diminta
$ request.query - Array - daftar parameter GET
$ request.headers - Array - daftar header permintaan
$ request.cookies - Array - daftar cookie
$ reuqest.auth - Array or Null - data untuk otentikasi HTTP
$ request.format - String - format data permintaan
$ request.data - ketik apa saja - apa yang dihitung di bidang
data$ Struktur tanggapan
$ response.network - Boolean - false jika kesalahannya berada pada level jaringan di bawah HTTP
$ response.code - Number atau Null - kode respons, misalnya, 200 atau 404
$ response.status - String atau Null - status respons, misalnya, "204 Tidak Ada Konten" atau "401 Tidak Sah"
$ response.headers - Array - daftar header respons, nama-nama header lebih kecil
$ response.cookies - Array - daftar cookie
$ response.body - semua tipe - tubuh respons diproses sebagai JSON, jika ada kesalahan selama parsing, maka tidak akan ada elemen
tubuh sama sekali:
@response.body == null
(
tentang memeriksa keberadaan variabel )
$ response.raw - String atau Null - badan respons mentah
$ response.duration - type Number - durasi permintaan dalam detik
Pembuatan model dan data uji
Generator digunakan untuk menggambarkan model dan menghasilkan data uji dari mereka. Deskripsi dalam format YAML harus dalam file
generators.yaml di direktori kerja dan / atau
* .yaml file di subdirektori
./generators .
User: body: login: Faker\login() name: Faker\name() email: Faker\email() password: Faker\text(16) child: Child() birthday: dateFormat(Faker\datetime(), "U") settings: notifications_enabled: Faker\boolean() Child: body: name: Faker\name() gender: Faker\integer(1, 2) age: Faker\integer(0, 18) Comment($user): body: content: "Hi! I'm " + $user.name tags: - "tag1" - "tag2"
Dalam contoh di atas, tiga generator
Pengguna () ,
Anak (), dan
Komentar () dideklarasikan. Dalam kasus ini, yang terakhir memiliki argumen
$ user dan dapat menggunakan data ini saat membuat. Argumen untuk generator selalu disahkan oleh nilai. Selain itu, contoh ini menggunakan beberapa fungsi
bawaan lainnya :
Faker \ name () ,
Faker \ email () ,
dateFormat () , dll.
Bagian tentang fungsi bawaan .
Saat memanggil generator
Pengguna () dari contoh di atas, sebuah struktur akan dibuat yang terlihat seperti ini di JSON:
{ "login": "fgadrkq", "name": "Lucy Cechtelar", "email": "tkshlerin@collins.com", "password": "gbnaueyaaf", "child": { "name": "Adaline Reichel", "gender": 2, "age": 12 }, "birthday": 318038400, "settings": { "notifications_enabled": true } }
Nilai bidang
anak adalah hasil dari generator
Anak () .
Seperti dalam uraian metode API, string apa pun yang tidak dicantumkan dalam tanda kutip diperlakukan sebagai ekspresi untuk dievaluasi. Ini bukan hanya panggilan ke generator lain, tetapi ekspresi sewenang-wenang, misalnya, dalam generator
Comment ($ user) , bidang
konten mewakili rangkaian string Hai! Saya dan nama diteruskan ke
$ penggunaNama-nama generator tidak peka huruf besar-kecil dan harus dimulai dengan huruf Latin, yang dapat berisi huruf Latin, angka, garis bawah, dan garis miring terbalik.
Karena sintaks untuk memanggil generator dan fungsi bawaan adalah sama, mereka berbagi ruang nama yang sama. Dengan konvensi, saya sarankan menggunakan backslash sebagai pemisah untuk menentukan "vendor" atau pustaka fungsi
bawaan , seperti fungsi Faker \ something (), berdasarkan pustaka
github.com/fzaninotto/Faker .
Nuansa menggunakan generator, Anda tidak bisa membacaMenggunakan generator, Anda dapat menyusun struktur data:
# Userredentials $user Userredentials($user): body: login: $user.email password: $user.password # . , GlobalSearchResult($posts, $comments, $users): body: posts: title: " " list: $posts comments: title: " " list: $comments users: title: " " list: $users
GlobalSearchResult bukan data uji yang dikirim dalam permintaan ke metode API, tetapi model respons yang dapat diverifikasi dengan apa yang akan dikirimkan oleh API, misalnya, menggunakan fungsi yang
serupa () atau
identik () .
Generator dapat mengubah struktur yang diperoleh dalam
tubuh menggunakan struktur yang dihitung dalam bidang
ganti dan
hapus . Saya akan tunjukkan contoh.
Misalkan Anda sudah memiliki generator
Pengguna () yang membuat struktur data yang benar untuk pengguna. Sekarang Anda perlu memeriksa bagaimana API akan merespons jika Anda memberikan data yang salah. Anda bisa menggunakan dua cara:
- Buat generator pengguna yang "salah" dari awal. Tetapi kemudian kita akan mendapatkan duplikasi kode, dan kemudian, misalnya, ketika menambahkan bidang baru ke pengguna sesuai dengan kebutuhan logika bisnis, Anda harus membuat perubahan di dua tempat. KERING!
- Anda dapat "mewarisi" dari struktur Pengguna () yang ada dengan mengaturnya di tubuh . Dan dalam mengganti dan menghapus, atur bidang yang akan ditambahkan / diubah dan dihapus.
# , , # InvalidUser($user): body: $user replace: email: Faker\String(6, 15) # password: Faker\String(1, 5) # new_field: " , " remove: name: size($user.name) < 10 # , 10 # , # InvalidNewUser: body: User() replace: login: "!@#$%^&*" # remove: about: true settings: notifications: 100500 # , # true
Ketika generator bekerja, struktur data dalam
tubuh pertama kali dihitung, kemudian ditimpa dan ditambah dengan elemen dari
ganti, dan kemudian bidang yang ditentukan dalam
penghapusan dihapus jika nilainya setara dengan
true . Jika hasil perhitungan
body ,
ganti atau
hapus bukan array, maka tidak akan ada kesalahan, tetapi juga tidak ada gunanya, karena tidak akan ada bidang yang bisa diganti dan dihapus.
Fungsi bawaan
Daftar lengkap fungsi bawaan . Sebagai contoh, saya hanya akan memberikan beberapa dari mereka.
Setelah nama fungsi dan daftar argumen,
jenis nilai kembali ditunjukkan, jika ada yang ditentukan.
Operasi dengan variabel:
mirip ($ var, $ sample, $ checkTypes)
Boolean - mengembalikan
true jika argumennya bertipe sama, jika
$ var adalah array, maka semua kunci string yang ada dalam
$ sample harus dalam
$ var , jika
$ checkTypes benar, maka jenis elemen yang sesuai harus cocok. Dengan kata lain, elemen-elemen dari array
$ var adalah subset dari elemen-elemen dari
$ sample .
identik ($ var, $ sample, $ checkTypes) Boolean adalah analog yang mirip () , dengan tambahan converse, dalam hal array, semua kunci string dalam $ var harus dalam $ sample juga . Dengan kata lain, elemen-elemen dari $ var array sama dengan elemen-elemen dari $ sample array hingga tipe elemen.maks ($ var1, $ var2, ... $ varN) - nilai maksimum yang diteruskan (jika dapat dibandingkan).min ($ var1, $ var2, ... $ varN) - minimum dari nilai yang diteruskan.if ($ condition, $ var1, $ var2) - Jika $ condition == true, maka ia akan mengembalikan $ var1, jika tidak $ var2. Mengganti operator pelatihan (halo MySQL).pilihan ($ condition1, $ var1, $ condition2, $ var2, ..., $ conditionN, $ varN) - Akan mengembalikan $ varK yang pertama ditemui jika $ conditionK == true.Bekerja dengan string:
size ($ string) Number - panjang string dalam pengkodean UTF-8.regex ($ string, $ regex) Boolean - periksa string untuk ekspresi reguler .regexMatch ($ string, $ regex) Array - akan mengembalikan array string - cocok dengan grup biasa $ regex .Pengolahan array:
array ($ var1, $ var2, ... $ varN) Array - membuat array dari elemen yang diteruskan.size ($ array) Number - jumlah elemen dalam array.keys ($ array) Array - daftar kunci dalam array.slice ($ array, $ offset, $ length) Array - bagian dari array dari $ offset panjang $ length, ( lebih banyak ).append ($ array, $ value) Array - menambahkan elemen ke akhir array.prepend ($ array, $ value) Array - menambahkan elemen ke awal array.Pengolahan tanggal:
dateFormat ($ date, $ format) String - format tanggal, ( lebih lanjut tentang format ).dateModify ($ date, $ format) Date - ubah tanggal, mudah digunakan dengan Format Relatif .Pembuatan data uji acak:
Faker \ integer ($ min, $ max) Nomor itu - integer acak antara $ min sampai $ max, inklusifFaker \ ipv4 () String - acak IPv4Faker \ arrayElement ($ array) String - elemen acak dari sebuah arrayFaker \ nama () String - nama acakFaker \ email () String - email acakSekarang tidak ada banyak fungsi bawaan. Saya menambahkan hanya apa yang menurut saya perlu saat pengujian. Anda dapat menambahkan fitur baru sesuai kebutuhan dalam versi baru. Dan di masa depan, jika dibutuhkan, saya akan menambahkan kemampuan untuk membuat fungsi yang terhubung secara dinamis diimplementasikan sebagai kelas khusus dalam PHP.Uji kasus
Kasus uji adalah urutan pernyataan yang dapat disebut sebagai unit. Beberapa analog dari prosedur dalam bahasa pemrograman.Sebuah test case dibuat oleh pernyataan testcase , diikuti oleh nama case test, dengan sintaksis yang mirip dengan nama metode API . Kasus uji bersarang dilarang. testcase Registration $device
Pernyataan run dapat memanggil kasus uji terpisah, atau semua kasus uji yang tidak memerlukan argumen. run Get all users
Gagasan peluncuran tersebut adalah bahwa kasus uji dapat digunakan sebagai tes independen terpisah dari bagian logika bisnis dan sebagai prosedur untuk menghindari duplikasi kode dalam skenario pengujian yang kompleks.Argumen diteruskan ke kasus uji dengan referensi atau dengan nilai dalam analogi lengkap melewati argumen ke metode API.Variabel dan Cakupan
Nama variabel peka huruf besar kecil dan mulai dengan tanda $ (ya, ya, saya seorang pshpshnik).Jika jenis variabel Array , maka akses ke bidang individu atau unsur-unsur nilai dihasilkan melalui titik: $users.12.password
. Antara titik, hanya angka atau huruf Latin, garis bawah dan angka dengan huruf Latin pertama yang diizinkan. Nama bidang juga peka huruf besar-kecil.Akses dinamis ke elemen array dimungkinkan:$post.comments[$i + 1].content
Ada empat jenis konteks - ruang lingkup variabel.Konteks global - dibuat di awal, berisi semua variabel yang dideklarasikan saat menjalankan pernyataan di luar kasus uji dan di luar panggilan metode API.Konteks test case - yang baru dibuat setiap kali test case dieksekusi dengan menjalankan pernyataan .Konteks metode API - dibuat ketika metode API dipanggil, ketika operator yang ditentukan di bagian sebelum dan sesudah dijalankan .Konteks Generator- tidak ada kemungkinan dalam generator untuk membuat variabel baru atau mengubah yang ada, oleh karena itu variabel konteks global dan argumen hanya baca-saja. Variabel selalu diteruskan oleh nilai ke konteks generator.Catatan penting. Dalam semua konteks, variabel konteks global tersedia jika namanya tidak dibuat dalam konteks saat ini.Contoh operator untuk bekerja dengan variabel: const $a = 1 let $a = 2
let $a = 1; $a = $a + 1; $a = $a + 2 print $a
Testcase Context example changes $argument1, $argument2 and $argument3 var $a = "changed" let $b = "changed" const $c = "changed" import $i let $i = "changed" var $argument1 = "changed" var $argument2 = "changed" var $argument3 = "changed"
Ketik Sistem dan Operasi
Lax dynamic typing digunakan.Nilai disimpan dalam pembungkus di atas jenis PHP yang sesuai. Untuk pemahaman yang lebih baik, lihat sistem tipe PHP. Saya membuat sedikit kebebasan dalam konversi tipe dinamis. Misalnya, saat menambahkan string dan angka "2" + 2
, kesalahan akan dihasilkan, dan PHP akan diam-diam melakukan penambahan. Mungkin saya perlu merevisi aturan pengetikan dinamis di masa mendatang, tetapi sejauh ini saya telah mencoba menemukan keseimbangan antara kenyamanan dan ketelitian yang dibutuhkan untuk pengujian yang andal.Jenis Data Tersedia dalam PieceofScript:NomorAdalah angka. Untuk alasan kesederhanaan, saya tidak membuat tipe terpisah untuk Integer dan Float. Satu-satunya perbedaan signifikan antara bilangan bulat dan bilangan real dalam PieceofScript adalah penggunaan array sebagai kunci: bilangan real akan dibulatkan menjadi bilangan bulat.7 -42 3.14159
String - string terlampir dalam tanda kutip ganda, mungkin lolos dengan slash"I say \"Hello world!\""
Null - ditetapkan oleh konstanta case-insensitivenull
Boolean - adalah hasil dari operasi Boolean dan operasi perbandingan, yang ditetapkan oleh konstanta case-insensitivetrue false
Tanggal - tanggal dan waktu. "Di balik tudung" adalah DateTime . Konstanta ditentukan dalam tanda kutip tunggal, dalam salah satu format .'now', '2008-08-07 18:11:31', 'last day of next month'
Array adalah array, satu-satunya tipe non-skalar. BungkusArray . Tidak ada literal jenis ini, tetapi array dapat merupakan hasil kerja generator, fungsi bawaan (misalnya, array () - halo PHP 5.3 dan di bawah), atau Anda dapat dengan mudah mengakses kunci variabel yang akan dibuat secara dinamis pada saat penugasan. let $a.1 = 100 let $i = 1 let $a[$i + 1] = 200 let $a.sum = $a.1 + $a.2 print " "; $a.sum // 300 var $b = array(true, 3, $a, "Hi") // [true, 3, {1: 100, 2: 200, "sum":300}, "Hi"]
Saat mengakses variabel atau elemen array yang tidak ada, skrip pengujian akan dihentikan dan kesalahan akan dihasilkan. Tetapi ketika menjalankan pernyataan tegas atau harus , jika variabel tidak ada diakses, tidak akan ada kesalahan, tetapi pemeriksaan akan dianggap gagal.Memeriksa keberadaan dan jenis variabel
Kita harus menyebutkan secara terpisah konstruksi memeriksa keberadaan dan jenis variabel @ .Jika @ ditentukan dalam nama variabel dan bukan $ , maka hasil konstruksi ini akan menjadi salah satu dari:- string dengan nama tipe variabel atau tipe elemen array, jika kunci digunakan;
- null jika variabel tidak ditemukan dalam konteks yang dapat diakses atau elemen dengan kunci yang ditentukan dalam array tidak ada.
Desain ini dapat bermanfaat saat memeriksa struktur respons HTTP. var $a.string_field = "Hello World" var $a.number_field = 3.14 var $a.bool_field = true var $a.date_field = '+1 day' var $a.null_field = null var $a.array_field = array(1, "2") assert @a.string_field == "String" assert @a.number_field == "Number" assert @a.bool_field == "Boolean" assert @a.date_field == "Date" assert @a.null_field == "Null" assert @a.array_field == "Array" assert @a.array_field.0 == "Number" assert @a.array_field.1 == "String" assert @a.array_field.2 == null assert @notExistedVar == null
Atau dalam konstruksi seperti: assert @comment.optional_field && $comment.optional_field > 20
Operasi Boolean dioptimalkan pada operan pertama. Jika operan pertama salah , operasi && bahkan tidak akan mencoba menghitung operan kedua. Demikian pula dengan || .
Menyimpan data di antara proses
Saya menggunakan skrip terpisah tidak hanya untuk pengujian setelah menyelesaikan tugas, tetapi juga selama pengembangan. Saya menambah dan mengubah skrip ketika saya mengimplementasikan fitur. Kemudian skrip ini menjadi dasar untuk menulis kasus uji, tetapi selama pengembangan, seseorang harus membuat panggilan API yang sama berulang kali. Selain itu, setiap kali dalam skrip, membuat entitas baru dari awal (misalnya, mendaftarkan pengguna) adalah waktu yang lama, membuat sampah di database dan dengan cara apa pun mengganggu pengembangan. Oleh karena itu, saya memutuskan untuk menambahkan kemampuan untuk menyimpan dan mengembalikan nilai variabel antara mulai di penyimpanan nilai kunci.Menyimpan diaktifkan oleh opsi baris perintah --storage , yang menetapkan nama file penyimpanan: pos.phar run ./start.pos --storage=storage.yaml
Data disimpan dalam format YAML, yang membuatnya mudah dibaca dan diedit.storage \ get (string $ key, $ defaultValue, boolean $ saveValue = true) - jika kunci $ key tidak ada atau file penyimpanan tidak ditentukan, mengembalikan $ defaultValue. Jika tidak, ini mengembalikan nilai yang disimpan. Jika argumen $ saveValue benar dan kunci $ key tidak ditemukan, $ defaultValue akan ditulis di sana.storage \ set (string $ key, $ value) - menyimpan $ value dengan kunci $ key, dan mengembalikan $ value. Jika file penyimpanan belum disetel, ia hanya mengembalikan $ value.storage \ key (string $ regexp = null) Array- Mengembalikan array semua kunci yang tersedia. Jika argumen $ regexp bukan nol, maka kunci yang sesuai dengan ekspresi reguler ini akan dikembalikan. Jika file penyimpanan belum disetel, ia mengembalikan array kosong.Output ke stdout
PieceofScript dapat menghasilkan laporan dalam format JUnit dan HTML. Yang pertama diperlukan untuk integrasi dengan sistem CI / CD, misalnya Jenkins. Yang kedua adalah dengan mudah melihat sendiri hasil tes, misalnya, saat menguji secara lokal. File laporan dapat disetel saat startup: pos.phar run ./start.pos --junit=junit_report.xml --html=report.html
Contoh laporan HTMLBerbagai informasi tentang karya juru bahasa ditampilkan di stdout. Ada 5 level standar dari output informasi. Segala sesuatu yang ditampilkan pada tingkat yang sama juga ditampilkan pada yang lebih "banyak bicara" lainnya.Quiet - level paling "silent" diatur oleh opsi -q command line .Pada level ini, tidak ada output ke stdout, bahkan kesalahan penafsir kritis. Tetapi dengan kode pengembalian yang tidak nol, Anda dapat memahami bahwa ada yang salah.Normal adalah level standar, tanpa menentukan opsi.Pada level ini, kesalahan dihasilkan pada interpreter. Permintaan yang salah untuk metode API dan gagal menegaskan dan harus memeriksa .Verbose - set oleh opsi-v .Pada level ini, hasil dari pernyataan cetak ditampilkan .Sangat verbose - diatur oleh opsi -vv .Pada level ini, peringatan juru bahasa ditampilkan.Debug - diatur oleh opsi -vvv .Pada level ini, semua baris skrip yang dieksekusi ditampilkan. Semua permintaan dan jawaban metode API, hasil dari semua menegaskan dan harus memeriksa .Contohnya
Pepatah "Lebih baik melihat sekali daripada mendengar seratus kali" adalah benar dan dalam interpretasi "lebih baik melihat kode satu kali daripada membaca deskripsinya seratus kali". Saya menyiapkan dan meletakkan contoh-contoh di https://github.com/maximw/PosExamples repositori .Virustotal
Virustotal.com - layanan untuk memeriksa file dan tautan berbahaya. Dokumentasi API . Pengujian dilakukan untuk bagian publik API, dengan pengecualian metode komentar, karena Saya tidak ingin membuang sampah di API "pertarungan" nyata dengan data uji.Untuk mengakses API, Anda perlu mendaftar , mendapatkan kunci dan menambahkannya ke file Virustotal / globals.pos .Tes lari: pos.phar run ./Virustotal/start.pos
Che ada untuk exe-shnik terletak di repositori?Untuk pengujian, saya menyalin hiddeninput.exe dari komponen Konsol di repositori Symfony. File ini dapat dihapus, dan untuk pengujian gunakan ukuran lain hingga 32 mb.
Kue kering
Analog pasebin. Dokumentasi API .Untuk mengakses API yang perlu Anda daftarkan , dapatkan kunci dan tambahkan ke file Pastery / globals.pos .Tes lari: pos.phar run ./Pastery/start.pos
Patut dicatat bahwa dengan tes ini ditemukan bug dalam batas jumlah tampilan. Ini sudah diperbaiki oleh pengembang Pastery.Rick dan morty
Saya pikir serial animasi ini dikenal banyak orang, dan dicintai oleh banyak orang. Dokumentasi API . API terdiri dari tiga bagian Karakter, Lokasi, dan Episode yang hampir identik. Oleh karena itu, skenarionya hampir sama, dan lihat saja kasus uji hanyalah salah satu bagian.Tes lari: pos.phar run ./RickAndMorty/20MinutesTest.pos
Jika Anda mengetahui API publik yang akan menarik untuk diuji dengan cara ini, silakan tulis dalam email pribadi.Komentar dan rencana untuk masa depan, jika ada
0) Saya memiliki daftar perbaikan kecil dan besar yang belum saya butuhkan, tetapi dapat bermanfaat.Lihat daftar- Tambahkan laporan tentang kerja dalam format Json dengan kemungkinan penimpaan setelah beberapa skrip berjalan
- body replace remove
- , YAML
- HTTP- ,
- , run . .
- HTML- stdout, -vvv
- https
- application/x-www-form-urlencoded CURLFile . Guzzle 6,
- « »,
- API,
- HTML-, bootstrap- « », .
1) Untuk validasi model dalam respons API menggunakan generator, sejauh ini hanya ada dua fungsi - mirip () dan identik () . Validasi dengan mereka terlalu "canggung." Tentu saja, sudah mungkin untuk memvalidasi jawaban "dengan tangan", dan dalam beberapa kasus tidak mungkin dengan cara lain, tetapi saya ingin membuatnya lebih nyaman dan, jika mungkin, hindari memeriksa jawaban secara manual. Ada beberapa ide tentang bagaimana memungkinkan untuk menghasilkan dan memvalidasi model menggunakan deskripsi model yang sama, menghindari duplikasi. Namun sejauh ini ide-ide ini belum terbentuk sehingga Anda dapat mengimplementasikannya dalam kode.2) Saya pikir perancah untuk metode API berdasarkan deskripsi di OpenAPI ( Swagger ), RAML , koleksi akan sangat bergunaTukang pos . Tapi ini banyak pekerjaan yang layak untuk dilakukan jika PieceofScript sepadan.3) Akan menyenangkan untuk membuat plugin untuk beberapa IDE, dengan penyorotan kode dan pelengkapan otomatis. Penyelesaian otomatis nama kasus uji, metode API, operator dan variabel akan menjadi nyaman secara sederhana. Tapi dia belum "menggali" ke arah ini. Memahami pembuatan highlight untuk Sublime Text dan Language Server Protocol . Saya akan senang jika ada orang yang berpikiran sama sudah berpengalaman dalam hal-hal seperti itu.4) Saya tidak tahu apa prioritas untuk menempatkan kemampuan untuk membuat fungsi yang terhubung secara dinamisdiimplementasikan dalam PHP. Di satu sisi, semuanya sederhana di sana, cukup untuk menangani autoload dan membuat spesifikasi kelas dan ruang nama yang digunakan. Di sisi lain, fungsi kompleks dengan dependensi mereka pasti akan menyebabkan konflik namespace antara dependensi (dalam kasus terburuk, versi yang berbeda). Ada juga sesuatu untuk dipikirkan.5) Sistem pengujian yang baik menjalankan pengujian independen secara paralel. Sekarang ini dapat dilakukan dengan meluncurkan interpreter beberapa kali dengan file awal yang berbeda, di mana berbagai test case terhubung. Tetapi saya pikir kita perlu menanamkan ini di dalam interpreter itu sendiri dengan deteksi otomatis dari apa yang dapat diluncurkan secara paralel.PS Di satu sisi, karena ini adalah "kerajinan" saya, akan masuk akal untuk meletakkan posting di hub "Saya PR." Di sisi lain, saya tidak PR, tidak mengejar keuntungan komersial, hanya instrumen yang saya buat untuk diri saya sendiri, saya memutuskan untuk "menyisir" dan mengeluarkannya di depan umum.