F # pengembangan dan pengujian unit?

107

Saya baru saja mulai dengan F #, yang merupakan bahasa fungsional pertama saya. Saya telah bekerja secara quasi-eksklusif dengan C #, dan menikmati banyak bagaimana F # membuat saya memikirkan kembali bagaimana saya menulis kode. Satu aspek yang menurut saya agak membingungkan adalah perubahan dalam proses penulisan kode. Saya telah menggunakan TDD selama bertahun-tahun di C # sekarang, dan sangat menghargai tes unit untuk mengetahui di mana saya berada.

Sejauh ini, proses saya dengan F # adalah menulis beberapa fungsi, bermain dengan mereka dengan konsol interaktif sampai saya "cukup" yakin mereka bekerja, dan men-tweak & menggabungkan. Ini berfungsi dengan baik pada masalah skala kecil seperti Proyek Euler, tetapi saya tidak dapat membayangkan membangun sesuatu yang besar seperti itu.

Bagaimana orang mendekati pengujian unit dan membangun rangkaian pengujian untuk program F #? Apakah ada yang setara dengan TDD? Setiap petunjuk atau pemikiran dihargai.

Mathias
sumber
1
expert-fsharp.com/CodeSamples/Forms/… menunjukkan contoh sederhana penggunaan NUnit dengan F #.
itowlson
lihat stackoverflow.com/questions/1468772/…
Mauricio Scheffer
related: stackoverflow.com/questions/5667372/… (Unquote jauh lebih dari sekadar catatan kaki / komentar karena ada dalam set jawaban di halaman ini)
Ruben Bartelink
Satu hal yang hilang dalam jawaban ini adalah contoh yang tepat dari Foq, AutoFixture.AutoFoq dan AutoFixture.xUnit yang terkait dengan inferensi tipe F #. Lihat trelford.com/blog/post/test5.aspx dan trelford.com/blog/post/fstestlang.aspx untuk pencicip dan suatu hari saya akan menulis jawaban yang tepat di sini
Ruben Bartelink

Jawaban:

77

Pengembang yang digerakkan oleh pengujian seharusnya merasa betah dalam bahasa fungsional seperti F #: fungsi kecil yang memberikan hasil yang dapat diulang secara deterministik cocok untuk pengujian unit. Ada juga kemampuan dalam bahasa F # yang memfasilitasi tes menulis. Ambil, misalnya, Ekspresi Objek . Anda dapat dengan mudah menulis palsu untuk fungsi yang menerima inputnya sebagai tipe antarmuka.

Jika ada, F # adalah bahasa berorientasi objek kelas satu dan Anda dapat menggunakan alat dan trik yang sama yang Anda gunakan saat melakukan TDD di C #. Ada juga beberapa alat pengujian yang ditulis atau khusus untuk F #:

Matthew Podwysocki menulis seri hebat tentang pengujian unit dalam bahasa fungsional. Paman Bob juga menulis artikel yang memancing pemikiran di sini .

Ray Vernagus
sumber
9
Saya juga telah mengembangkan (dan secara aktif mengembangkan) pustaka pengujian unit khusus F # yang disebut Unquote: code.google.com/p/unquote . Ini memungkinkan Anda untuk menulis pernyataan pengujian sebagai ekspresi F # boolean yang biasa dan dicentang secara statis menggunakan F # Kutipan dan secara otomatis menghasilkan pesan kegagalan pengujian yang bagus. Ia bekerja tanpa konfigurasi dengan dukungan khusus untuk xUnit.net dan NUnit dan umumnya mendukung kerangka pengujian unit berbasis pengecualian. Ia bahkan bekerja dalam sesi FSI yang memungkinkan migrasi mulus dari pengujian interaktif ke rangkaian pengujian formal.
Stephen Swensen
Ada Pex juga, meski itu sedikit lebih sulit untuk didapatkan.
Benjol
1
Link paman bob tampaknya mati
Aage
22

Saya menggunakan NUnit, dan menurut saya tidak terlalu sulit untuk dibaca atau sulit ditulis:

open NUnit.Framework

[<TestFixture>]
type myFixture() = class

    [<Test>]
    member self.myTest() =
       //test code

end

Karena kode saya adalah campuran dari F # dan bahasa .Net lainnya, saya suka fakta bahwa saya menulis pengujian unit pada dasarnya dengan cara yang sama dan dengan sintaks yang serupa di F # dan C #.

David Glaubman
sumber
4
Setelah membaca tanggapan lain di sini, saya mencoba FSUnit, dan saya pikir itu bagus. Ia bekerja dengan baik dengan TestDriven.Net (seperti halnya NUnit), mendorong gaya penulisan tes dokumentasi mandiri yang lancar dan, seperti yang dinyatakan Ray, "lebih nyaman dalam bahasa F #". Tidak buruk untuk 21 baris kode! (Dan beberapa rekomendasi tata letak / penamaan). Dua catatan singkat: 1. FSUnit DLL yang telah dikompilasi tidak bekerja untuk saya. Membangun dari sumber (FsUnit.NUnit-0.9.0.fs) memperbaiki masalah. 2. TestDriven.Net tidak mengenali nama TextFixture yang terlihat `like this`. Nama tes menggunakan formulir centang ganda dikenali.
David Glaubman
15

Lihat FsCheck , alat pengujian otomatis untuk F #, pada dasarnya adalah port dari QuickCheck Haskell. Ini memungkinkan Anda untuk memberikan spesifikasi program, dalam bentuk properti yang harus dipenuhi oleh fungsi atau metode, dan FsCheck menguji properti tersebut dalam sejumlah besar kasus yang dibuat secara acak.

FsCheck Halaman CodePlex

FsCheck Halaman Penulis

primodemus
sumber
Ya, saya pikir FsCheck menawarkan lebih dari sekedar kerangka kerja pengujian unit tradisional seperti NUnit dll.
Robert
11

Seperti yang disarankan dglaubman, Anda dapat menggunakan NUnit. xUnit.net juga menyediakan dukungan untuk ini dan bekerja dengan baik dengan TestDriven.net . Kode tersebut terlihat mirip dengan pengujian NUnit tetapi tanpa persyaratan untuk menggabungkan pengujian dalam tipe yang memuatnya.

#light

// Supply a module name here not a combination of module and namespace, otherwise
// F# cannot resolve individual tests nfrom the UI.
module NBody.DomainModel.FSharp.Tests

open System
open Xunit

open Internal

[<Fact>]
let CreateOctantBoundaryReordersMinMax() =
    let Max = VectorFloat(1.0, 1.0, 1.0)
    let Min = VectorFloat(-1.0, -1.0, -1.0)

    let result = OctantBoundary.create Min Max

    Assert.Equal(Min, result.Min)     
    Assert.Equal(Max, result.Max) 
Ade Miller
sumber
Pada 1.9.1 overload baru Xunit tampaknya menyebabkan malapetaka dengan F # saya.
Rick Minerich
@RickMinerich Saya mengalami hal yang sama terjadi pada kode saya. Saya baru saja menambahkan anotasi tipe eksplisit sehingga kelebihan beban yang benar akan dipilih. Namun, sayangnya hal ini menambah lebih banyak gangguan pada kode Anda.
Erik Schierboom
11

Saya pikir ini adalah pertanyaan yang sangat menarik yang banyak saya tanyakan sendiri. Pikiran saya sejauh ini hanyalah pikiran, jadi ambillah apa adanya.

Saya pikir jaring pengaman dari rangkaian pengujian otomatis adalah aset yang terlalu berharga untuk dilepaskan, betapapun menariknya konsol interaktif itu, jadi saya berencana untuk terus menulis pengujian unit seperti yang selalu saya lakukan.

Salah satu kekuatan utama .NET adalah kemampuan lintas bahasa. Saya tahu saya akan segera menulis kode produksi F #, tetapi rencana saya adalah menulis pengujian unit dalam C # untuk memudahkan jalan saya ke dalam bahasa baru bagi saya. Dengan cara ini, saya juga bisa menguji bahwa apa yang saya tulis di F # akan kompatibel dengan C # (dan bahasa .NET lainnya).

Dengan pendekatan ini, saya memahami bahwa ada fitur tertentu dari F # yang hanya dapat saya gunakan secara internal dalam kode F # saya, tetapi tidak diekspos sebagai bagian dari API publik saya, tetapi saya akan menerimanya, seperti yang saya terima hari ini bahwa ada hal-hal tertentu C # memungkinkan saya untuk mengekspresikan (suka uint) yang tidak sesuai dengan CLS, jadi saya menahan diri untuk tidak menggunakannya.

Mark Seemann
sumber
2
Bagaimana rencanamu? Mudah untuk menguji kode f # dengan kode c #? Saya mulai belajar f # dan rencana saya adalah menulis beberapa bagian dari proyek saya di f # dan saya memiliki ide yang sama: menulis pengujian unit di c # untuk f # juga.
Peter Porfy
@ Tandai pembaruan? Saya juga mengalami kesulitan untuk menggunakan TDD dengan F #.
Scott Nimrod
1
@ScottNimrod Beberapa pembaruan: empat kursus Pluralsight saya adalah tentang pengujian atau TDD dengan F #. Anda juga akan menemukan banyak rekaman pembicaraan konferensi gratis di profil Lanyrd saya . Akhirnya, ada blog saya .
Mark Seemann
3
@ScottNimrod Saya tidak dapat merekomendasikan meluangkan waktu dan / atau membayar uang untuk melihat set lengkap kursus PS Markus dengan cukup tinggi - itu akan menyatukan semuanya di kepala Anda dengan efisiensi maksimum. Meskipun mungkin atau mungkin tidak berlaku untuk kebutuhan spesifik Anda, "Arsitektur Fungsional di F #" juga menghubungkan banyak titik dan juga harus sangat dipertimbangkan.
Ruben Bartelink
7

Anda dapat melihat FSUnit - meskipun saya belum menggunakannya, mungkin patut dicoba. Tentunya lebih baik daripada menggunakan misalnya (asli) NUnit di F #.

ShdNx
sumber
1
ShdNx, mengapa Anda merekomendasikan terhadap NUnit? Buku F # Don Syme menunjukkan NUnit untuk pengujian dan terlihat sangat mirip dengan menggunakan NUnit di C #. FSUnit DSL terlihat keren, tapi bagi orang yang sudah familiar dengan NUnit (Mathias telah "menggunakan TDD selama bertahun-tahun") apakah pengalaman Anda bahwa menggunakan NUnit dengan F # lebih bermasalah daripada dengan C # atau VB?
itowlson
Saya kedua itowlson komentar, dan pertanyaan. Hampir pasti NUnit di F # terlihat sangat aneh, tetapi selain itu, apakah Anda mengetahui masalah tertentu yang menjadikannya ide yang bagus untuk menggunakan yang lain?
Mathias
1
Saya akan mengatakan bahwa "terlihat sangat aneh" biasanya merupakan alasan kuat untuk menemukan sesuatu yang lebih baik. Tampak aneh berarti sulit dibaca, dan sulit dibaca berarti bug. (Saya berasumsi bahwa "terlihat aneh" sama sekali berbeda dari "terlihat baru dan / atau tidak biasa" - tidak biasa akan menjadi akrab, aneh akan tetap aneh.)
James Moore
1
Sejujurnya (seperti yang saya sebutkan dalam tanggapan saya), saya belum menggunakan FSUnit, tetapi saya telah membaca bahwa sangat menyakitkan menggunakan NUnit di F #. Maaf jika tidak demikian.
ShdNx
4
Untuk lebih jelasnya, Anda masih akan memiliki TestFixtures dan Test member jika Anda menggunakan FsUnit. Apa yang tidak Anda miliki adalah panggilan Assert.X standar. FsUnit hanya memberi Anda pembungkus di sekitar bagian NUnit ini yang membuatnya lebih nyaman dalam bahasa F #.
Ray Vernagus
1

Meskipun agak terlambat ke pesta, saya ingin menyambut Mathias ke F # (lebih baik terlambat daripada tidak sama sekali;)) dan berpadu bahwa Anda mungkin menyukai pustaka pengujian unit saya, Expecto

Expecto memiliki beberapa fitur yang mungkin Anda sukai:

  • F # sintaks seluruh, tes sebagai nilai; tulis F # untuk menghasilkan tes
  • Gunakan modul Expect bawaan, atau lib eksternal seperti Unquote untuk pernyataan
  • Tes paralel secara default
  • Uji kode Hopac atau kode Async Anda; Expecto asinkron seluruhnya
  • Pencatatan dan metrik yang dapat dicolok melalui Logary Facade; tulis adaptor dengan mudah untuk sistem build, atau gunakan mekanisme pengaturan waktu untuk membuat dasbor InfluxDB + Grafana dari waktu eksekusi pengujian Anda
  • Dukungan bawaan untuk BenchmarkDotNet
  • Bangun dukungan untuk FsCheck; memudahkan untuk membuat pengujian dengan data yang dihasilkan / acak atau membuat model-invarian dari ruang status objek / aktor Anda

-

open Expecto

let tests =
  test "A simple test" {
    let subject = "Hello World"
    Expect.equal subject "Hello World" "The strings should equal"
  }

[<EntryPoint>]
let main args =
  runTestsWithArgs defaultConfig args tests

https://github.com/haf/expecto/

Henrik
sumber