การพัฒนา F # และการทดสอบหน่วย?


107

ฉันเพิ่งเริ่มใช้ F # ซึ่งเป็นภาษาแรกที่ใช้งานได้ ฉันทำงานกึ่งเดียวกับ C # และสนุกมากกับการที่ F # ทำให้ฉันคิดใหม่ว่าฉันเขียนโค้ดอย่างไร สิ่งหนึ่งที่ฉันพบว่ามีความสับสนเล็กน้อยคือการเปลี่ยนแปลงในกระบวนการเขียนโค้ด ตอนนี้ฉันใช้ TDD ใน C # มาหลายปีแล้วและรู้สึกขอบคุณมากที่มีการทดสอบหน่วยเพื่อให้ทราบว่าฉันอยู่ที่ไหน

จนถึงตอนนี้กระบวนการของฉันกับ F # คือการเขียนฟังก์ชั่นบางอย่างเล่นกับคอนโซลแบบโต้ตอบจนกว่าฉันจะ "มีเหตุผล" แน่ใจว่ามันใช้งานได้และปรับแต่งและรวมเข้าด้วยกัน สิ่งนี้ใช้ได้ดีกับปัญหาเล็ก ๆ เช่นโครงการออยเลอร์ แต่ฉันนึกไม่ถึงว่าจะสร้างสิ่งที่ใหญ่ขนาดนั้นได้

ผู้คนเข้าถึงการทดสอบหน่วยและสร้างชุดทดสอบสำหรับโปรแกรม F # ได้อย่างไร มีเทียบเท่ากับ TDD หรือไม่? คำแนะนำหรือความคิดใด ๆ ที่ได้รับการชื่นชม


1
expert-fsharp.com/CodeSamples/Forms/…แสดงตัวอย่างง่ายๆของการใช้ NUnit กับ F #
itowlson


ที่เกี่ยวข้อง: stackoverflow.com/questions/5667372/… (Unquote เป็นมากกว่าเชิงอรรถ / แสดงความคิดเห็นเนื่องจากอยู่ในชุดคำตอบในหน้านี้)
Ruben Bartelink

สิ่งหนึ่งที่ขาดหายไปในคำตอบเหล่านี้คือตัวอย่างที่เหมาะสมของ Foq, AutoFixture.AutoFoq และ AutoFixture.xUnit เป็นพันธมิตรกับการอนุมานประเภท F # ดูtrelford.com/blog/post/test5.aspxและtrelford.com/blog/post/fstestlang.aspxสำหรับนักชิมและสักวันฉันจะเขียนคำตอบที่ถูกต้องที่นี่
Ruben Bartelink

คำตอบ:


77

นักพัฒนาที่ได้รับการทดสอบควรรู้สึกเหมือนอยู่บ้านในภาษาที่ใช้งานได้เช่น F #: ฟังก์ชันขนาดเล็กที่ให้ผลลัพธ์ที่ทำซ้ำได้อย่างแน่นอนช่วยให้สามารถทดสอบหน่วยได้อย่างสมบูรณ์แบบ นอกจากนี้ยังมีความสามารถในภาษา F # ที่อำนวยความสะดวกในการทดสอบการเขียน ใช้ตัวอย่างเช่น, นิพจน์วัตถุ คุณสามารถเขียนของปลอมสำหรับฟังก์ชันที่ใช้เป็นอินพุตประเภทอินเทอร์เฟซได้อย่างง่ายดาย

ถ้ามีอะไร F # เป็นภาษาเชิงวัตถุชั้นหนึ่งและคุณสามารถใช้เครื่องมือและลูกเล่นเดียวกับที่คุณใช้เมื่อทำ TDD ใน C # นอกจากนี้ยังมีเครื่องมือทดสอบบางอย่างที่เขียนขึ้นโดยเฉพาะสำหรับ F #:

Matthew Podwysocki เขียนซีรีส์ที่ยอดเยี่ยมเกี่ยวกับการทดสอบหน่วยในภาษาที่ใช้งานได้ ลุงบ๊อบยังเขียนบทความกระตุ้นความคิดที่นี่


9
ฉันยังได้พัฒนา (และกำลังแข็งขันพัฒนา) ความ F # เฉพาะห้องสมุดทดสอบหน่วยที่เรียกว่านำมาอ้าง: code.google.com/p/unquote ช่วยให้คุณสามารถเขียนคำยืนยันการทดสอบเป็นนิพจน์บูลีน F # ที่ตรวจสอบแบบคงที่โดยใช้ F # Quotations และสร้างข้อความความล้มเหลวในการทดสอบที่ดีโดยอัตโนมัติ ใช้งานได้โดยไม่ต้องกำหนดค่าด้วยการสนับสนุนพิเศษสำหรับทั้ง xUnit.net และ NUnit และโดยทั่วไปสนับสนุนกรอบการทดสอบหน่วยตามข้อยกเว้น มันยังใช้งานได้ภายในเซสชัน FSI ทำให้สามารถย้ายข้อมูลจากการทดสอบแบบโต้ตอบไปยังชุดทดสอบอย่างเป็นทางการ
Stephen Swensen

มีPexด้วยเช่นกันแม้ว่าจะยากกว่าเล็กน้อยที่จะคราง
เบญจพล

1
ลิงค์ลุงบ๊อบดูเหมือนจะตาย
Aage

22

ฉันใช้ NUnit และมันไม่ได้ทำให้ฉันอ่านยากหรือเขียนยาก:

open NUnit.Framework

[<TestFixture>]
type myFixture() = class

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

end

เนื่องจากโค้ดของฉันเป็นการผสมผสานระหว่าง F # และภาษา. Net อื่น ๆ ฉันจึงชอบความจริงที่ว่าฉันเขียนการทดสอบหน่วยในรูปแบบเดียวกันโดยทั่วไปและมีไวยากรณ์ที่คล้ายกันทั้งใน F # และ C #


4
หลังจากอ่านคำตอบอื่น ๆ ที่นี่ฉันได้ลอง FSUnit และฉันคิดว่ามันเยี่ยมมาก ทำงานได้ดีกับ TestDriven.Net (เช่นเดียวกับ NUnit) ส่งเสริมรูปแบบการเขียนแบบทดสอบเอกสารด้วยตนเองที่ลื่นไหลและในฐานะที่เป็นของ Ray ก็คือ "ภาษา F # ที่บ้าน" ไม่เลวสำหรับโค้ด 21 บรรทัด! (และคำแนะนำการจัดวาง / การตั้งชื่ออีกสองสามข้อ) บันทึกย่อสองข้อ: 1. FSUnit DLL ที่คอมไพล์ไว้ล่วงหน้าไม่ได้ผลสำหรับฉัน การสร้างจากซอร์ส (FsUnit.NUnit-0.9.0.fs) แก้ไขปัญหา 2. TestDriven.Net ไม่รู้จักชื่อ TextFixture `like this`ที่มีลักษณะ รู้จักชื่อการทดสอบโดยใช้แบบฟอร์มขีดสองครั้ง
David Glaubman

15

ลองดูFsCheckซึ่งเป็นเครื่องมือทดสอบอัตโนมัติสำหรับ F # นั้นเป็นพอร์ต QuickCheck ของ Haskell ช่วยให้คุณสามารถระบุข้อมูลจำเพาะของโปรแกรมในรูปแบบของคุณสมบัติที่ฟังก์ชันหรือวิธีการควรตอบสนองและ FsCheck ทดสอบว่าคุณสมบัติมีอยู่ในกรณีที่สร้างแบบสุ่มจำนวนมาก

หน้า FsCheck CodePlex

หน้าผู้เขียน FsCheck


ใช่ฉันคิดว่า FsCheck มีมากกว่ากรอบการทดสอบหน่วยแบบเดิม ๆ เช่น NUnit เป็นต้น
Robert

11

ตามที่ dglaubman แนะนำคุณสามารถใช้ NUnit xUnit.netยังให้การสนับสนุนนี้และทำงานได้ดีกับTestDriven.net รหัสมีลักษณะคล้ายกับการทดสอบ NUnit แต่ไม่มีข้อกำหนดในการรวมการทดสอบในประเภทที่มี

#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) 

จากการโอเวอร์โหลดใหม่ของ Xunit 1.9.1 ดูเหมือนจะสร้างความเสียหายให้กับ F # ของฉัน
Rick Minerich

@RickMinerich ฉันเคยมีประสบการณ์แบบเดียวกันกับรหัสของฉัน ฉันเพิ่งเพิ่มคำอธิบายประกอบประเภทที่ชัดเจนเพื่อให้เลือกโอเวอร์โหลดที่ถูกต้อง อย่างไรก็ตามสิ่งนี้จะเพิ่มเสียงรบกวนให้กับโค้ดของคุณมากขึ้น
Erik Schierboom

11

ฉันคิดว่านี่เป็นคำถามที่น่าสนใจที่ฉันเคยสงสัยเกี่ยวกับตัวเองมามาก ความคิดของฉันจนถึงตอนนี้เป็นเพียงความคิดดังนั้นจงยึดมั่นในสิ่งที่เป็น

ฉันคิดว่าเครือข่ายความปลอดภัยของชุดทดสอบอัตโนมัติมีค่าเกินกว่าที่จะปล่อยไปได้อย่างไรก็ตามคอนโซลแบบโต้ตอบนั้นอาจมีเสน่ห์ดังนั้นฉันจึงวางแผนที่จะเขียนการทดสอบหน่วยต่อไปเหมือนที่ฉันเคยทำมาตลอด

จุดแข็งหลักอย่างหนึ่งของ. NET คือความสามารถข้ามภาษา ฉันรู้ว่าฉันกำลังจะเขียนรหัสการผลิต F # ในเร็ว ๆ นี้ แต่แผนของฉันคือการเขียนการทดสอบหน่วยใน C # เพื่อให้ฉันเข้าใจภาษาใหม่สำหรับฉันได้ง่ายขึ้น ด้วยวิธีนี้ฉันยังได้ทดสอบว่าสิ่งที่ฉันเขียนใน F # จะเข้ากันได้กับ C # (และภาษา. NET อื่น ๆ )

ด้วยวิธีนี้ฉันเข้าใจว่ามีคุณลักษณะบางอย่างของ F # ที่ฉันสามารถใช้ได้ภายในรหัส F # ของฉันเท่านั้น แต่จะไม่เปิดเผยเป็นส่วนหนึ่งของ API สาธารณะของฉัน แต่ฉันจะยอมรับสิ่งนั้นเช่นเดียวกับที่ฉันยอมรับในวันนี้ว่ามีบางอย่าง C # ช่วยให้ฉันสามารถแสดง (ชอบuint) ที่ไม่สอดคล้องกับ CLS ดังนั้นฉันจึงไม่ใช้มัน


2
แผนของคุณเป็นอย่างไร? การทดสอบรหัส f # ด้วยรหัส c # เป็นเรื่องง่ายหรือไม่? ฉันเริ่มเรียนรู้ f # และแผนการของฉันคือเขียนบางส่วนของโปรเจ็กต์ของฉันใน f # และฉันก็มีความคิดเดียวกันคือเขียนแบบทดสอบหน่วยใน c # สำหรับ f # ด้วย
Peter Porfy

@ ทำเครื่องหมายการอัปเดตใด ๆ ? ฉันยังประสบปัญหาในการใช้ TDD กับ F #
Scott Nimrod

1
@ScottNimrod อัปเดตค่อนข้างน้อย: หลักสูตร Pluralsightสี่หลักสูตรของฉันเกี่ยวกับการทดสอบหรือ TDD กับ F # นอกจากนี้คุณยังจะพบจำนวนมากของการบันทึกฟรีของการเจรจาการประชุมเกี่ยวกับรายละเอียด Lanyrd ของฉัน ในที่สุดก็มีบล็อกของฉัน
Mark Seemann

3
@ScottNimrod ฉันไม่สามารถแนะนำให้สละเวลาและ / หรือจ่ายเงินเพื่อดูชุดวิชา PS ของ Mark ให้มากพอ - มันจะรวมเข้าด้วยกันในหัวของคุณอย่างมีประสิทธิภาพสูงสุด แม้ว่าจะใช้กับความต้องการเฉพาะของคุณหรือไม่ก็ได้ แต่ "A Functional Architecture in F #" ยังเชื่อมโยงจุดต่างๆมากมายและควรได้รับการพิจารณาอย่างยิ่ง
Ruben Bartelink

7

คุณสามารถดูFSUnit - แม้ว่าฉันจะยังไม่ได้ใช้มันก็น่าลอง แน่นอนว่าดีกว่าการใช้ตัวอย่าง (เนทีฟ) NUnit ใน F #


1
ShdNx ทำไมคุณถึงแนะนำ NUnit? หนังสือ F # ของ Don Syme แสดง NUnit สำหรับการทดสอบและดูคล้ายกับการใช้ NUnit ใน C # FSUnit DSL ดูดี แต่สำหรับผู้ที่คุ้นเคยกับ NUnit อยู่แล้ว (Mathias "ใช้ TDD มาหลายปีแล้ว") เป็นประสบการณ์ของคุณหรือไม่ว่าการใช้ NUnit กับ F # มีปัญหามากกว่า C # หรือ VB
itowlson

ฉันสอง itowlson แสดงความคิดเห็นและคำถาม NUnit ที่แน่นอนที่สุดใน F # ดูแปลก ๆ แต่นอกจากนั้นคุณยังตระหนักถึงปัญหาเฉพาะที่ทำให้ควรใช้อย่างอื่นหรือไม่?
Mathias

1
ฉันจะบอกว่า "ดูแปลก ๆ " มักเป็นเหตุผลที่น่าสนใจในการค้นหาสิ่งที่ดีกว่า การมองแปลกหมายถึงอ่านยากและอ่านยากหมายถึงข้อบกพร่อง (ฉันสมมติว่า "ดูแปลก" แตกต่างอย่างสิ้นเชิงกับ "ดูใหม่และ / หรือไม่คุ้นเคย" - คนที่ไม่คุ้นเคยจะกลายเป็นความคุ้นเคยความแปลกจะยังคงแปลกอยู่)
เจมส์มัวร์

1
พูดตามตรง (ตามที่ฉันได้กล่าวไว้ในคำตอบของฉัน) ฉันยังไม่ได้ใช้ FSUnit แต่ฉันได้อ่านพบว่าการใช้ NUnit ใน F # นั้นเจ็บปวดมาก ขออภัยหากไม่เป็นเช่นนั้น
ShdNx

4
เพื่อความชัดเจนคุณจะยังคงมี TestFixtures และ Test Members อยู่หากคุณใช้ FsUnit สิ่งที่คุณจะไม่มีคือการเรียก Assert.X มาตรฐาน FsUnit ช่วยให้คุณมี wrapper รอบ ๆ ส่วนนี้ของ NUnit ซึ่งทำให้มันเป็นที่บ้านมากขึ้นในภาษา F #
Ray Vernagus

1

แม้ว่าจะไปงานปาร์ตี้ช้าไปหน่อย แต่ฉันก็อยากจะต้อนรับ Mathias เข้าสู่ F # (ดีกว่าไม่มาสายเลย;)) และเสียงระฆังที่คุณอาจชอบ Expecto ไลบรารีการทดสอบหน่วยของฉัน

Expecto มีคุณสมบัติบางอย่างที่คุณอาจชอบ:

  • ไวยากรณ์ F # ตลอดการทดสอบเป็นค่า เขียน F # ธรรมดาเพื่อสร้างการทดสอบ
  • ใช้โมดูล Expect ในตัวหรือ lib ภายนอกเช่น Unquote สำหรับการยืนยัน
  • การทดสอบคู่ขนานตามค่าเริ่มต้น
  • ทดสอบรหัส Hopac หรือรหัส Async ของคุณ Expecto ไม่ตรงกันตลอด
  • การบันทึกและเมตริกแบบเสียบได้ผ่าน Logary Facade เขียนอะแด็ปเตอร์สำหรับสร้างระบบหรือใช้กลไกเวลาในการสร้างแดชบอร์ด InfluxDB + Grafana ของเวลาดำเนินการทดสอบของคุณ
  • สร้างขึ้นในการสนับสนุน BenchmarkDotNet
  • สร้างเพื่อรองรับ FsCheck; ทำให้ง่ายต่อการสร้างการทดสอบด้วยข้อมูลที่สร้างขึ้น / สุ่มหรือการสร้างแบบจำลองที่ไม่แปรเปลี่ยนของพื้นที่สถานะของวัตถุ / นักแสดงของคุณ

-

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/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.