F # phát triển và thử nghiệm đơn vị?


107

Tôi mới bắt đầu với F #, là ngôn ngữ chức năng đầu tiên của tôi. Tôi đã làm việc gần như độc quyền với C # và rất thích cách F # dẫn tôi đến việc suy nghĩ lại cách tôi viết mã. Một khía cạnh tôi thấy hơi mất phương hướng là sự thay đổi trong quá trình viết mã. Bây giờ tôi đã sử dụng TDD trong nhiều năm trong C # và thực sự đánh giá cao việc thực hiện các bài kiểm tra đơn vị để biết vị trí của tôi.

Cho đến nay, quá trình của tôi với F # là viết một số chức năng, chơi với chúng bằng bảng điều khiển tương tác cho đến khi tôi "hợp lý" chắc chắn rằng chúng hoạt động, và tinh chỉnh & kết hợp. Điều này hoạt động tốt với các vấn đề quy mô nhỏ như Dự án Euler, nhưng tôi không thể tưởng tượng việc xây dựng một cái gì đó lớn theo cách đó.

Làm cách nào để mọi người tiếp cận kiểm thử đơn vị và xây dựng bộ kiểm thử cho chương trình F #? Có tương đương với TDD không? Mọi ý kiến ​​hoặc suy nghĩ đều được đánh giá cao.


1
Expert-fsharp.com/CodeSamples/Forms/… cho thấy một ví dụ đơn giản về việc sử dụng NUnit với F #.
itowlson


liên quan: stackoverflow.com/questions/5667372/... (unquote là nhiều hơn so với một chú thích / bình luận vì nó nằm trong answerset trên trang này)
Ruben Bartelink

Một điều còn thiếu trong các câu trả lời này là một ví dụ thích hợp về Foq, AutoFixture.AutoFoq và AutoFixture.xUnit liên minh với kiểu suy luận của F #. Xem trelford.com/blog/post/test5.aspxtrelford.com/blog/post/fstestlang.aspx cho một người nếm và một ngày nào đó tôi sẽ viết một câu trả lời thích hợp ở đây
Ruben Bartelink

Câu trả lời:


77

Các nhà phát triển theo hướng kiểm tra sẽ cảm thấy thoải mái như ở nhà bằng các ngôn ngữ chức năng như F #: các hàm nhỏ cung cấp kết quả có thể lặp lại một cách xác định cho phép họ hoàn toàn phù hợp với các bài kiểm tra đơn vị. Ngoài ra còn có các khả năng trong ngôn ngữ F # hỗ trợ các bài kiểm tra viết. Lấy ví dụ, Biểu thức đối tượng . Bạn rất có thể dễ dàng viết giả mạo cho các chức năng lấy đầu vào của chúng như một kiểu giao diện.

Nếu có, F # là ngôn ngữ hướng đối tượng hạng nhất và bạn có thể sử dụng các công cụ và thủ thuật tương tự như bạn sử dụng khi thực hiện TDD trong C #. Ngoài ra còn có một số công cụ kiểm tra được viết bằng hoặc dành riêng cho F #:

Matthew Podwysocki đã viết một loạt bài tuyệt vời về kiểm thử đơn vị bằng các ngôn ngữ chức năng. Chú Bob cũng đã viết một bài báo kích thích suy nghĩ ở đây .


9
Tôi cũng đã phát triển (và đang tích cực phát triển) một thư viện kiểm tra đơn vị cụ thể của F # có tên là Unquote: code.google.com/p/unquote . Nó cho phép bạn viết các xác nhận kiểm tra dưới dạng các biểu thức boolean F # được kiểm tra tĩnh, sử dụng F # Quotations và tự động tạo ra các thông báo lỗi kiểm tra đẹp. Nó hoạt động không cần cấu hình với hỗ trợ đặc biệt cho cả xUnit.net và NUnit và thường hỗ trợ bất kỳ khung thử nghiệm đơn vị dựa trên ngoại lệ nào. Nó thậm chí còn hoạt động trong các phiên FSI cho phép di chuyển liền mạch từ thử nghiệm tương tác sang các bộ thử nghiệm chính thức.
Stephen Swensen

Có cả Pex nữa, mặc dù điều đó khó tìm hiểu hơn một chút.
Benjol

1
Bác bob liên kết có vẻ đã chết
Aage

22

Tôi sử dụng NUnit và nó không khiến tôi khó đọc hoặc khó viết:

open NUnit.Framework

[<TestFixture>]
type myFixture() = class

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

end

Vì mã của tôi là sự kết hợp của F # và các ngôn ngữ .Net khác, nên tôi thích thực tế là tôi viết các bài kiểm tra đơn vị về cơ bản giống nhau và với cú pháp tương tự trong cả F # và C #.


4
Sau khi đọc các phản hồi khác ở đây, tôi đã dùng thử FSUnit và tôi nghĩ nó thật tuyệt. Nó hoạt động tốt với TestDriven.Net (cũng như NUnit), khuyến khích phong cách viết các bài kiểm tra tự lập tài liệu linh hoạt và như Ray nói, là "ngôn ngữ F # ở nhà nhiều hơn". Không tồi cho 21 dòng mã! (Và một vài đề xuất về bố cục / đặt tên). Hai lưu ý nhanh: 1. FSUnit DLL được biên dịch trước không hoạt động với tôi. Xây dựng từ nguồn (FsUnit.NUnit-0.9.0.fs) đã khắc phục sự cố. 2. TestDriven.Net không nhận dạng được các tên TextFixture `like this`. Tên bài kiểm tra sử dụng hình thức đánh dấu hai lần được công nhận.
David Glaubman

15

Hãy xem FsCheck , một công cụ kiểm tra tự động cho F #, về cơ bản là một cổng QuickCheck của Haskell. Nó cho phép bạn cung cấp đặc điểm kỹ thuật của chương trình, dưới dạng thuộc tính mà các hàm hoặc phương thức phải đáp ứng, và kiểm tra FsCheck rằng các thuộc tính đó có trong một số lượng lớn các trường hợp được tạo ngẫu nhiên.

FsCheck CodePlex Trang

Trang tác giả FsCheck


Vâng, tôi nghĩ FsCheck cung cấp nhiều hơn các khuôn khổ kiểm tra đơn vị truyền thống như NUnit, v.v.
Robert

11

Như dglaubman gợi ý bạn có thể sử dụng NUnit. xUnit.net cũng cung cấp hỗ trợ cho việc này và hoạt động tốt với TestDriven.net . Mã trông tương tự như các bài kiểm tra NUnit nhưng không có yêu cầu bao bọc bài kiểm tra trong một loại có chứa.

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

Kể từ 1.9.1 tình trạng quá tải mới của Xunit dường như đang gây ra sự tàn phá với F # của tôi.
Rick Minerich,

@RickMinerich Tôi đã gặp điều tương tự xảy ra với mã của mình. Tôi vừa kết thúc việc thêm các chú thích kiểu rõ ràng để quá tải chính xác sẽ được chọn. Tuy nhiên, điều này không may gây thêm nhiễu cho mã của bạn.
Erik Schierboom

11

Tôi nghĩ đây là một câu hỏi rất thú vị mà bản thân tôi đã tự hỏi rất nhiều. Suy nghĩ của tôi từ trước đến nay chỉ là suy nghĩ, vì vậy hãy coi chúng là gì.

Tôi nghĩ rằng mạng lưới an toàn của một bộ thử nghiệm tự động là một tài sản quá giá trị để bỏ qua, tuy nhiên, bảng điều khiển tương tác đó có thể hấp dẫn, vì vậy tôi dự định tiếp tục viết các bài kiểm tra đơn vị như tôi đã từng làm.

Một trong những điểm mạnh chính của .NET là khả năng đa ngôn ngữ. Tôi biết mình sẽ sớm viết mã sản xuất F #, nhưng kế hoạch của tôi là viết các bài kiểm tra đơn vị bằng C # để dễ dàng tiếp cận ngôn ngữ mới đối với tôi. Bằng cách này, tôi cũng có thể kiểm tra xem những gì tôi viết bằng F # sẽ tương thích với C # (và các ngôn ngữ .NET khác).

Với cách tiếp cận này, tôi hiểu rằng có một số tính năng nhất định của F # mà tôi chỉ có thể sử dụng nội bộ trong mã F # của mình, nhưng không được tiết lộ như một phần của API công khai của tôi, nhưng tôi sẽ chấp nhận điều đó, cũng như hôm nay tôi chấp nhận rằng có một số điều C # cho phép tôi thể hiện (giống như uint) không tuân thủ CLS, và vì vậy tôi không sử dụng chúng.


2
Kế hoạch của bạn diễn ra như thế nào? Kiểm tra mã f # với mã c # có dễ không? Tôi bắt đầu học f # và kế hoạch của tôi là viết một số phần trong dự án của tôi bằng f # và tôi có cùng ý tưởng: viết các bài kiểm tra đơn vị trong c # cho cả f #.
Peter Porfy

@ Đánh dấu bất kỳ cập nhật nào? Tôi cũng gặp khó khăn khi sử dụng TDD với F #.
Scott Nimrod

1
@ScottNimrod Có một vài cập nhật: bốn trong số các khóa học Pluralsight của tôi là về kiểm tra hoặc TDD với F #. Bạn cũng sẽ tìm thấy nhiều bản ghi âm miễn phí các cuộc hội đàm trên hồ sơ Lanyrd của tôi . Cuối cùng, có blog của tôi .
Mark Seemann

3
@ScottNimrod Tôi không thể khuyên bạn nên dành thời gian và / hoặc trả tiền để xem trọn bộ các khóa học PS của Mark đủ cao - nó sẽ thu gọn tất cả lại trong đầu bạn với hiệu quả tối đa. Mặc dù nó có thể áp dụng hoặc có thể không áp dụng cho các nhu cầu cụ thể của bạn, nhưng "Kiến trúc chức năng trong F #" cũng kết nối rất nhiều dấu chấm và cũng cần được xem xét kỹ lưỡng.
Ruben Bartelink

7

Bạn có thể xem qua FSUnit - mặc dù tôi chưa sử dụng nó nhưng nó có thể đáng để thử. Chắc chắn tốt hơn là sử dụng NUnit ví dụ (gốc) trong F #.


1
ShdNx, tại sao bạn lại khuyên bạn không nên sử dụng NUnit? Cuốn sách F # của Don Syme cho thấy NUnit để thử nghiệm và nó trông khá giống với việc sử dụng NUnit trong C #. FSUnit DSL trông rất tuyệt, nhưng đối với những người đã quen thuộc với NUnit (Mathias đã "sử dụng TDD trong nhiều năm") thì kinh nghiệm của bạn rằng việc sử dụng NUnit với F # có vấn đề hơn với C # hoặc VB?
itowlson

Tôi thứ hai nhận xét itowlson, và câu hỏi. Chắc chắn nhất là NUnit trong F # trông khá kỳ quặc, nhưng bên cạnh đó, bạn có biết về các vấn đề cụ thể khiến bạn nên sử dụng thứ gì khác không?
Mathias

1
Tôi muốn nói rằng "trông khá kỳ quặc" thường là một lý do thuyết phục để tìm thứ gì đó tốt hơn. Nhìn kỳ cục có nghĩa là khó đọc, và khó đọc có nghĩa là lỗi. (Tôi giả định rằng "tìm lẻ" là hoàn toàn khác biệt so với "tìm kiếm mới và / hoặc không quen thuộc" - không quen thuộc sẽ trở nên quen thuộc, lẻ sẽ ở lại lẻ.)
James Moore

1
Thành thật mà nói (như tôi đã đề cập trong phản hồi của mình), tôi chưa sử dụng FSUnit, nhưng tôi đã đọc rằng rất khó sử dụng NUnit trong F #. Xin lỗi nếu nó không phải như vậy.
ShdNx

4
Nói rõ hơn, bạn vẫn sẽ có TestFixtures và thành viên Test nếu bạn sử dụng FsUnit. Những gì bạn sẽ không có là các cuộc gọi Assert.X tiêu chuẩn. FsUnit chỉ đơn giản là cung cấp cho bạn một trình bao bọc xung quanh phần này của NUnit để làm cho nó giống như ở nhà bằng ngôn ngữ F #.
Ray Vernagus

1

Mặc dù đến bữa tiệc hơi muộn, tôi muốn chào mừng Mathias đến với F # (muộn còn hơn không;)) và kêu vang rằng bạn có thể thích thư viện thử nghiệm đơn vị của tôi, Expecto

Expecto có một số tính năng mà bạn có thể thích:

  • Cú pháp F # xuyên suốt, kiểm tra dưới dạng giá trị; viết F # thuần túy để tạo các bài kiểm tra
  • Sử dụng mô-đun Expect tích hợp sẵn hoặc một lib bên ngoài như Unquote cho các xác nhận
  • Kiểm tra song song theo mặc định
  • Kiểm tra mã Hopac hoặc mã Async của bạn; Expecto không đồng bộ trong suốt
  • Ghi nhật ký và số liệu dễ hiểu thông qua Logary Facade; dễ dàng viết các bộ điều hợp để xây dựng hệ thống hoặc sử dụng cơ chế thời gian để xây dựng trang tổng quan InfluxDB + Grafana về thời gian thực hiện các thử nghiệm của bạn
  • Hỗ trợ tích hợp cho BenchmarkDotNet
  • Xây dựng hỗ trợ cho FsCheck; giúp dễ dàng tạo các bài kiểm tra với dữ liệu được tạo / ngẫu nhiên hoặc xây dựng các mô hình bất biến của không gian trạng thái của đối tượng / tác nhân của bạn

-

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/

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.