Tabel data

Blok where dan tabel data yang menggerakkan banyak kasus dalam satu metode uji.

Daftar isi

Blok where membuat satu metode uji Spock mengerjakan banyak kasus sekaligus. Setiap baris data yang dideklarasikan menghasilkan satu kali eksekusi penuh dari blok harapannya, sehingga logika pengujian cukup ditulis sekali. Topik ini membahas tabel data pada blok where, mulai dari data pipe, pemisah || antara kolom masukan dan kolom harapan, variabel komputasi, hingga beberapa variabel dalam satu baris. Setelah itu menyusul pengaturan nama iterasi melalui @Unroll dan @Rollup, nilai khusus _ untuk data yang diabaikan, serta cara membaca pesan error ketika salah satu baris gagal.

Tabel data pada blok where#

Blok where selalu ditulis paling akhir di dalam metode uji dan wajib dipasangkan dengan blok expect atau then yang mendahuluinya. Blok yang berpasangan itu dieksekusi satu kali untuk setiap baris pada blok where, sehingga empat baris data menghasilkan empat kali eksekusi tanpa satu baris kode uji pun yang disalin ulang. Nilai setiap kolom dikirim melalui data pipe, yaitu operator << yang mengalirkan anggota sebuah list ke variabel data, satu anggota untuk satu eksekusi.

Ketika beberapa variabel disusun menjadi tabel, setiap kolom berperan sebagai satu variabel data dan setiap baris sebagai satu kasus uji. Batas antarkolom ditulis dengan tanda |, sedangkan tanda || memisahkan kolom masukan dari kolom harapan. Kolom di sebelah kiri || diberikan kepada kode uji sebagai masukan, dan kolom di sebelah kanannya menyimpan nilai yang diharapkan. Perataan spasi antarsel bebas karena Spock hanya membaca posisi tanda pipa, sehingga tabel boleh dirapikan sesuai selera.

groovy klasifikasi-nilai.groovy
// klasifikasi-nilai.groovy: tabel data dengan pemisah ||
@Grab('org.spockframework:spock-core:2.4-groovy-5.0')
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import spock.lang.Specification

class KlasifikasiNilaiSpec extends Specification {
    def "klasifikasi nilai ujian"() {
        expect:
        huruf(nilai) == ekspektasi

        where:
        nilai || ekspektasi
        95    || 'A'
        85    || 'A'
        74    || 'B'
        45    || 'C'
    }

    def "jumlah dua bilangan"() {
        expect:
        a + b == hasil

        where:
        a  | b  || hasil
        2  | 3  || 5
        10 | 20 || 30
    }

    String huruf(int nilai) {
        if (nilai >= 85) return 'A'
        if (nilai >= 70) return 'B'
        return 'C'
    }
}

// menjalankan seluruh spesifikasi lewat launcher JUnit Platform
def jalankan(Class spec) {
    def launcher = LauncherFactory.create()
    def permintaan = LauncherDiscoveryRequestBuilder.request()
        .selectors(DiscoverySelectors.selectClass(spec))
        .build()
    launcher.execute(permintaan, new TestExecutionListener() {
        void executionFinished(TestIdentifier id, TestExecutionResult hasil) {
            if (!id.isTest() || id.isContainer()) return
            String status = hasil.status == TestExecutionResult.Status.SUCCESSFUL ? 'LULUS' : 'GAGAL'
            println "${status} ${id.displayName}"
        }
    })
}

jalankan(KlasifikasiNilaiSpec)
text Keluaran
LULUS klasifikasi nilai ujian [nilai: 95, ekspektasi: A, #0]
LULUS klasifikasi nilai ujian [nilai: 85, ekspektasi: A, #1]
LULUS klasifikasi nilai ujian [nilai: 74, ekspektasi: B, #2]
LULUS klasifikasi nilai ujian [nilai: 45, ekspektasi: C, #3]
LULUS jumlah dua bilangan [a: 2, b: 3, hasil: 5, #0]
LULUS jumlah dua bilangan [a: 10, b: 20, hasil: 30, #1]

Keluaran memperlihatkan enam iterasi dari dua metode uji. Metode klasifikasi menyumbang empat iterasi sesuai jumlah barisnya, sedangkan metode penjumlahan menambah dua iterasi dari tabelnya yang memakai dua kolom masukan sekaligus, yaitu a dan b. Nama setiap iterasi memuat nilai barisnya, misalnya [nilai: 74, ekspektasi: B, #2] untuk baris ketiga, pola yang dibedah pada bagian @Unroll. Iterasi juga berjalan berurutan sesuai urutan barisnya, sehingga kegagalan mudah dilacak kembali ke baris sumbernya.

Setiap berkas contoh pada topik ini memanggil launcher JUnit Platform pada bagian bawahnya, sehingga seluruhnya dapat dijalankan langsung dengan perintah groovy dari terminal. Dependensi spock-core diambil melalui @Grab dengan koordinat org.spockframework:spock-core:2.4-groovy-5.0 yang mengikuti Groovy 5, dan launcher JUnit Platform ikut hadir sebagai dependensi transitifnya sehingga tidak perlu @Grab tambahan.

bash
# tidak-dijalankan
# menjalankan satu berkas contoh dari terminal
groovy klasifikasi-nilai.groovy

Variabel komputasi#

Tabel bukan satu-satunya bentuk yang diterima blok where. Setiap barisnya boleh berupa penyedia data (data provider) tersendiri, yaitu satu variabel yang menerima nilai dari sisi kanan <<, dan bagian kanannya boleh berisi ekspresi apa pun yang menghasilkan list, misalnya pemanggilan metode atau hasil collect. Bentuk satu kolom ini cocok ketika data ujinya berupa satu rangkaian nilai, sedangkan tabel lebih tepat ketika beberapa variabel perlu dibaca berdampingan.

Variabel di dalam blok where juga dapat dihitung dari variabel yang sudah ada melalui penugasan biasa dengan tanda =. Bentuk ini disebut variabel komputasi (computed data variable), dan nilainya dihitung ulang pada setiap iterasi dari nilai variabel baris tersebut. Variabel komputasi tidak perlu ditulis di dalam tabel, cukup ditulis pada baris di bawahnya, dan nilainya tetap tampil pada nama iterasi.

groovy konversi-suhu.groovy
// konversi-suhu.groovy: data pipe dan variabel komputasi
@Grab('org.spockframework:spock-core:2.4-groovy-5.0')
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import spock.lang.Specification

class KonversiSuhuSpec extends Specification {
    def "konversi celsius ke fahrenheit"() {
        expect:
        keFahrenheit(celsius) == fahrenheit

        where:
        celsius << [0, 25, 100, -40]
        fahrenheit = celsius * 9 / 5 + 32
    }

    def keFahrenheit(int celsius) {
        celsius * 1.8 + 32
    }
}

// menjalankan seluruh spesifikasi lewat launcher JUnit Platform
def jalankan(Class spec) {
    def launcher = LauncherFactory.create()
    def permintaan = LauncherDiscoveryRequestBuilder.request()
        .selectors(DiscoverySelectors.selectClass(spec))
        .build()
    launcher.execute(permintaan, new TestExecutionListener() {
        void executionFinished(TestIdentifier id, TestExecutionResult hasil) {
            if (!id.isTest() || id.isContainer()) return
            String status = hasil.status == TestExecutionResult.Status.SUCCESSFUL ? 'LULUS' : 'GAGAL'
            println "${status} ${id.displayName}"
        }
    })
}

jalankan(KonversiSuhuSpec)
text Keluaran
LULUS konversi celsius ke fahrenheit [celsius: 0, fahrenheit: 32, #0]
LULUS konversi celsius ke fahrenheit [celsius: 25, fahrenheit: 77, #1]
LULUS konversi celsius ke fahrenheit [celsius: 100, fahrenheit: 212, #2]
LULUS konversi celsius ke fahrenheit [celsius: -40, fahrenheit: -40, #3]

Skrip di atas menguji keFahrenheit dengan empat titik suhu. Kolom fahrenheit dihitung dari celsius melalui rumus celsius * 9 / 5 + 32, sedangkan metode yang diuji ditulis dengan rumus lain yang setara, yaitu celsius * 1.8 + 32. Keduanya ditulis berbeda tetapi menghasilkan nilai yang sama, sehingga kesalahan pada salah satunya langsung terlihat pada iterasi yang gagal. Keluaran juga memperlihatkan nilai komputasi ikut muncul pada nama iterasi, misalnya fahrenheit: 77 untuk celsius 25.

Beberapa variabel dalam satu baris#

Satu baris data kadang perlu mengisi lebih dari satu variabel sekaligus. Data pipe multi-variabel menuliskan daftar variabelnya di dalam tanda kurung siku, misalnya [teks, jumlah] <<, dan setiap baris berupa list yang anggotanya dibagikan ke variabel-variabel itu sesuai posisinya. Tipe antaranggota tidak harus sama, sehingga baris ['satu dua tiga', 3] yang menggabungkan String dan Integer sah digunakan.

Bentuk kedua adalah penugasan berganda (bilangan, kuadrat) = baris. Penugasan ini mengurai satu variabel data menjadi beberapa variabel baru, dan hasilnya setara dengan data pipe multi-variabel. Bentuk ini berguna ketika baris sudah tersedia sebagai satu kesatuan, misalnya hasil pembacaan satu baris berkas CSV, tetapi blok harapan lebih nyaman memakai variabel yang sudah terurai.

groovy penghitung-kata.groovy
// penghitung-kata.groovy: multi-variabel dan penugasan berganda
@Grab('org.spockframework:spock-core:2.4-groovy-5.0')
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import spock.lang.Specification

class PenghitungKataSpec extends Specification {
    def "hitung kata dalam satu baris teks"() {
        expect:
        jumlahKata(teks) == jumlah

        where:
        [teks, jumlah] << [
            ['satu dua tiga', 3],
            ['groovy dan spock', 3],
            ['belajar', 1],
        ]
    }

    def "kuadrat dari penugasan berganda"() {
        expect:
        bilangan ** 2 == kuadrat

        where:
        baris << [[2, 4], [5, 25], [11, 121]]
        (bilangan, kuadrat) = baris
    }

    int jumlahKata(String teks) {
        teks.trim().split(/\s+/).size()
    }
}

// menjalankan seluruh spesifikasi lewat launcher JUnit Platform
def jalankan(Class spec) {
    def launcher = LauncherFactory.create()
    def permintaan = LauncherDiscoveryRequestBuilder.request()
        .selectors(DiscoverySelectors.selectClass(spec))
        .build()
    launcher.execute(permintaan, new TestExecutionListener() {
        void executionFinished(TestIdentifier id, TestExecutionResult hasil) {
            if (!id.isTest() || id.isContainer()) return
            String status = hasil.status == TestExecutionResult.Status.SUCCESSFUL ? 'LULUS' : 'GAGAL'
            println "${status} ${id.displayName}"
        }
    })
}

jalankan(PenghitungKataSpec)
text Keluaran
LULUS hitung kata dalam satu baris teks [teks: satu dua tiga, jumlah: 3, #0]
LULUS hitung kata dalam satu baris teks [teks: groovy dan spock, jumlah: 3, #1]
LULUS hitung kata dalam satu baris teks [teks: belajar, jumlah: 1, #2]
LULUS kuadrat dari penugasan berganda [baris: [2, 4], bilangan: 2, kuadrat: 4, #0]
LULUS kuadrat dari penugasan berganda [baris: [5, 25], bilangan: 5, kuadrat: 25, #1]
LULUS kuadrat dari penugasan berganda [baris: [11, 121], bilangan: 11, kuadrat: 121, #2]

Fitur pertama membagi setiap baris list ke teks dan jumlah, lalu membandingkan hasil metode jumlahKata dengan nilai yang diharapkan. Fitur kedua menerima baris utuh melalui pipe baris, kemudian mengurainya menjadi bilangan dan kuadrat melalui penugasan berganda. Keluaran memperlihatkan enam iterasi lulus, dan nama iterasinya menampilkan nilai terurai sekaligus nilai aslinya, misalnya baris: [2, 4], bilangan: 2, kuadrat: 4, sehingga kedua bentuk penulisan variabel dapat dibandingkan langsung.

Nama iterasi: @Unroll dan @Rollup#

Sejak Spock 2.0, setiap baris tabel dilaporkan sebagai uji terpisah secara default, sehingga jumlah uji pada laporan sama dengan jumlah barisnya, dengan maupun tanpa anotasi @Unroll. Perilaku ini disebut unrolling. Pada bentuk default, nama iterasi berpola nama metode [variabel: nilai, ..., #indeks], sebagaimana terlihat pada keluaran bagian sebelumnya.

Anotasi @Unroll digunakan untuk mengganti pola nama default dengan nama pilihan sendiri melalui interpolasi #variabel. Pada spesifikasi berikut, pola #nilai dikali dua sama dengan #hasil menggantikan pola kurung siku bawaan, sehingga setiap baris laporan terbaca seperti kalimat. Interpolasi #variabel bekerja bahkan tanpa anotasi karena unrolling memang berjalan secara default, tetapi anotasi tetap berguna untuk menegaskan niat penulis dan untuk mengaktifkan kembali unrolling pada konfigurasi yang menonaktifkannya.

Anotasi @Rollup bergerak ke arah sebaliknya, yaitu menyatukan seluruh baris menjadi satu entri laporan yang namanya hanya berisi nama metode. Bentuk ini dipilih ketika rincian per baris dianggap tidak penting, misalnya untuk tabel yang panjangnya ratusan baris.

groovy nama-iterasi.groovy
// nama-iterasi.groovy: pola nama default, @Unroll, dan @Rollup
@Grab('org.spockframework:spock-core:2.4-groovy-5.0')
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import spock.lang.Rollup
import spock.lang.Specification
import spock.lang.Unroll

class NamaIterasiSpec extends Specification {
    def "tanpa anotasi"() {
        expect:
        nilai * 2 == hasil

        where:
        nilai | hasil
        3     | 6
        5     | 10
    }

    @Unroll('#nilai dikali dua sama dengan #hasil')
    def "dengan anotasi"() {
        expect:
        nilai * 2 == hasil

        where:
        nilai | hasil
        3     | 6
        5     | 10
    }

    @Rollup
    def "dengan rollup"() {
        expect:
        nilai * 2 == hasil

        where:
        nilai | hasil
        3     | 6
        5     | 10
    }
}

// menjalankan seluruh spesifikasi lewat launcher JUnit Platform
def jalankan(Class spec) {
    def launcher = LauncherFactory.create()
    def permintaan = LauncherDiscoveryRequestBuilder.request()
        .selectors(DiscoverySelectors.selectClass(spec))
        .build()
    launcher.execute(permintaan, new TestExecutionListener() {
        void executionFinished(TestIdentifier id, TestExecutionResult hasil) {
            if (!id.isTest() || id.isContainer()) return
            String status = hasil.status == TestExecutionResult.Status.SUCCESSFUL ? 'LULUS' : 'GAGAL'
            println "${status} ${id.displayName}"
        }
    })
}

jalankan(NamaIterasiSpec)
text Keluaran
LULUS tanpa anotasi [nilai: 3, hasil: 6, #0]
LULUS tanpa anotasi [nilai: 5, hasil: 10, #1]
LULUS 3 dikali dua sama dengan 6
LULUS 5 dikali dua sama dengan 10
LULUS dengan rollup

Keluaran memuat lima entri dari tiga metode uji. Metode tanpa anotasi dilaporkan sebagai dua uji bernama tanpa anotasi [nilai: 3, hasil: 6, #0] dan seterusnya, metode beranotasi @Unroll tampil sebagai dua uji bernama kalimat, sedangkan metode @Rollup cukup satu uji bernama dengan rollup. Jumlah iterasi yang benar-benar dieksekusi tetap dua untuk ketiganya, dan yang berbeda hanya cara pelaporannya.

Baris yang gagal dan nilai yang diabaikan#

Kegagalan pada satu baris hanya menggagalkan iterasinya sendiri, sedangkan baris lain tetap dieksekusi sampai selesai. Pesan errornya berupa Condition not satisfied yang diikuti diagram nilai pada baris yang gagal, sehingga penyebabnya dapat dibaca langsung dari laporan tanpa membuka debugger.

groovy tabel-gagal.groovy
// tabel-gagal.groovy: satu baris keliru dan nilai yang diabaikan
@Grab('org.spockframework:spock-core:2.4-groovy-5.0')
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import spock.lang.Specification

class TabelGagalSpec extends Specification {
    def "klasifikasi dengan satu baris keliru"() {
        expect:
        huruf(nilai) == ekspektasi

        where:
        nilai || ekspektasi
        95    || 'A'
        74    || 'A'   // keliru: 74 seharusnya B
        45    || 'C'
    }

    def "konversi fahrenheit ke celsius dengan kolom diabaikan"() {
        expect:
        keCelsius(fahrenheit) == celsius

        where:
        fahrenheit | celsius | _
        32         | 0       | _
        212        | 100     | _
    }

    String huruf(int nilai) {
        if (nilai >= 85) return 'A'
        if (nilai >= 70) return 'B'
        return 'C'
    }

    def keCelsius(int fahrenheit) {
        (fahrenheit - 32) / 1.8
    }
}

// menjalankan seluruh spesifikasi lewat launcher JUnit Platform
def jalankan(Class spec) {
    def launcher = LauncherFactory.create()
    def permintaan = LauncherDiscoveryRequestBuilder.request()
        .selectors(DiscoverySelectors.selectClass(spec))
        .build()
    launcher.execute(permintaan, new TestExecutionListener() {
        void executionFinished(TestIdentifier id, TestExecutionResult hasil) {
            if (!id.isTest() || id.isContainer()) return
            String status = hasil.status == TestExecutionResult.Status.SUCCESSFUL ? 'LULUS' : 'GAGAL'
            println "${status} ${id.displayName}"
            if (hasil.throwable.isPresent()) println hasil.throwable.get().message
        }
    })
}

jalankan(TabelGagalSpec)
text Keluaran
LULUS klasifikasi dengan satu baris keliru [nilai: 95, ekspektasi: A, #0]
GAGAL klasifikasi dengan satu baris keliru [nilai: 74, ekspektasi: A, #1]
Condition not satisfied:

huruf(nilai) == ekspektasi
|     |      |  |
B     74     |  A
             false
             1 difference (0% similarity)
             (B)
             (A)

LULUS klasifikasi dengan satu baris keliru [nilai: 45, ekspektasi: C, #2]
LULUS konversi fahrenheit ke celsius dengan kolom diabaikan [fahrenheit: 32, celsius: 0, #0]
LULUS konversi fahrenheit ke celsius dengan kolom diabaikan [fahrenheit: 212, celsius: 100, #1]

Pada iterasi kedua, huruf(74) mengembalikan B sedangkan ekspektasinya 'A', dan diagram pesan menampilkan semuanya, yaitu nilai kembalian B, isi nilai, isi ekspektasi, serta hasil perbandingan false. Baris pertama dan ketiga tetap tercatat LULUS, sehingga baris yang keliru terisolasi dengan pasti. Pola pesan yang sama berlaku untuk blok then maupun expect, karena keduanya memuat kondisi yang diperiksa pada setiap iterasi.

Tanda _ dipakai untuk nilai yang tidak dibutuhkan oleh spesifikasi. Kolom dengan header _ berisi penanda yang diabaikan Spock, sehingga variabelnya tidak muncul pada nama iterasi dan tidak boleh dirujuk oleh blok harapan. Tanda _ juga dapat menggantikan anggota pada data pipe multi-variabel, misalnya [a, _] <<, ketika hanya sebagian variabel yang dibutuhkan. Pada tabel konversi fahrenheit di berkas contoh, kolom _ sengaja ditambahkan untuk mencontohkan bentuk tersebut tanpa mengubah hasil pengujian.

Kesalahan umum#

Kesalahan pertama adalah menulis tabel yang berisi header saja tanpa satu baris data pun. Spock menolaknya saat kompilasi, jauh sebelum pengujian berjalan, dengan pesan Data table must have more than just the header row. Karena penolakan terjadi pada proses kompilasi, contoh berikut mengevaluasi spesifikasi bermasalah melalui GroovyShell, menangkap MultipleCompilationErrorsException, lalu mengekstrak baris pesan yang menyebut penyebabnya.

Kesalahan kedua adalah penyedia data yang panjangnya tidak sama. Iterasi pertama tetap dieksekusi dan bisa saja LULUS, tetapi begitu penyedia yang pendek kehabisan nilai, fitur berhenti dengan SpockExecutionException dan baris sisanya tidak pernah dijalankan.

groovy kesalahan-tabel.groovy
// kesalahan-tabel.groovy: tabel tanpa baris data dan penyedia data pendek
@Grab('org.spockframework:spock-core:2.4-groovy-5.0')
import org.codehaus.groovy.control.MultipleCompilationErrorsException
import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.engine.discovery.DiscoverySelectors
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import spock.lang.Specification

// tabel dengan header saja ditolak saat kompilasi
def skrip = '''
import spock.lang.Specification

class TabelKosongSpec extends Specification {
    def "tabel tanpa baris data"() {
        expect:
        true

        where:
        nilai || ekspektasi
    }
}
'''

try {
    new GroovyShell(this.class.classLoader).evaluate(skrip)
} catch (MultipleCompilationErrorsException e) {
    println "Gagal saat kompilasi: ${e.getClass().simpleName}"
    def m = (e.message =~ /Data table[^\n@]*/)
    if (m) println "Penyebab: ${m[0].trim()}"
}

println '---'

// penyedia data yang pendek menghentikan fitur di tengah eksekusi
class PenyediaPendekSpec extends Specification {
    def "penyedia data tidak sama panjang"() {
        expect:
        a + 1 == b

        where:
        a << [1, 2]
        b << [2]
    }
}

// menjalankan seluruh spesifikasi lewat launcher JUnit Platform
def jalankan(Class spec) {
    def launcher = LauncherFactory.create()
    def permintaan = LauncherDiscoveryRequestBuilder.request()
        .selectors(DiscoverySelectors.selectClass(spec))
        .build()
    launcher.execute(permintaan, new TestExecutionListener() {
        void executionFinished(TestIdentifier id, TestExecutionResult hasil) {
            if (!id.isTest()) return
            String jenis = id.isContainer() ? 'fitur' : 'iterasi'
            println "${hasil.status} (${jenis}) ${id.displayName}"
            if (hasil.throwable.isPresent()) {
                def t = hasil.throwable.get()
                println "PESAN : ${t.message}"
                println "JENIS : ${t.getClass().simpleName}"
            }
        }
    })
}

jalankan(PenyediaPendekSpec)
text Keluaran
Gagal saat kompilasi: MultipleCompilationErrorsException
Penyebab: Data table must have more than just the header row
---
SUCCESSFUL (iterasi) penyedia data tidak sama panjang [a: 1, b: 2, #0]
FAILED (fitur) penyedia data tidak sama panjang
PESAN : Data provider for variable 'b' has fewer values than previous data provider(s)
JENIS : SpockExecutionException

Keluaran memperlihatkan kedua kegagalan itu. Pesan Data table must have more than just the header row muncul saat kompilasi spesifikasi dengan tabel kosong, sedangkan penyedia b yang hanya berisi satu nilai menghentikan fitur setelah iterasi pertamanya LULUS. Perbaikan untuk keduanya sederhana, yaitu menambahkan baris data pada tabel yang kosong dan melengkapi penyedia yang pendek menjadi b << [2, 3].

Ringkasan#

  • Blok where ditulis paling akhir dan dipasangkan dengan expect atau then, lalu setiap baris datanya dieksekusi sebagai iterasi terpisah.
  • Nilai dikirim melalui data pipe << yang sisi kanannya boleh berupa list apa pun, variabel komputasi dengan tanda = dihitung ulang setiap iterasi, dan [teks, jumlah] << atau (a, b) = baris mengisi beberapa variabel dari satu baris.
  • Sejak Spock 2.0 unrolling berjalan secara default, @Unroll hanya mengganti pola nama melalui interpolasi #variabel, sedangkan @Rollup menyatukan seluruh baris menjadi satu entri laporan.
  • Tanda _ menandai nilai yang diabaikan, baris yang gagal menghasilkan pesan Condition not satisfied berisi nilai seluruh variabel barisnya, tabel tanpa baris data ditolak saat kompilasi, dan penyedia data pendek menghentikan fitur dengan SpockExecutionException.

Referensi#