2014-04-22 41 views
7

Sử dụng FsCheck, phiên bản F # của thư viện kiểm tra QuickCheck Haskell, để tạo thử nghiệm từ C#, tôi thấy rằng trình tạo chuỗi ngẫu nhiên không tạo chuỗi rỗng.Cách tạo chuỗi rỗng cho kiểm tra FsCheck

using FsCheck.Fluent; 
Spec.ForAny<string>(s => s != null).QuickCheck(); // always pass 

Hơn nữa, có vẻ như không xử lý chuỗi rỗng theo thiết kế, nhưng tôi chưa quản lý để ghim xuống from the documentation. Ví dụ, chỉ cần chọn giữa hai chuỗi, một trong số họ null, sẽ không làm việc:

var strings = Any.ValueIn<string>(null, "non-null string"); 
Spec.For(strings, s => true).QuickCheck(); // throws null ref exception 

Và chuỗi dường như là một trường hợp đặc biệt, vì nó xử lý đối tượng custom-made như

class Thing {} 

khi được trộn với giá trị null:

var objects = Any.ValueIn(null, new Thing()); 
Spec.For(objects, s => true).QuickCheck(); // pass 

Trả lời

4

Tôi đã cố gắng đào sâu một chút và có vẻ như bạn đã phát hiện ra lỗi trong FsCheck.

Dường như vấn đề nằm trong tệp Arbitrary.fs và thực sự chỉ liên quan đến chuỗi. Tôi đã phải thay thế này, nơi mà họ gọi ToCharArray trên chuỗi

static member String() = 
     { new Arbitrary<string>() with 
      override x.Generator = Gen.map (fun chars -> new String(List.toArray chars)) generate 
      override x.Shrinker s = s.ToCharArray() |> Array.toList |> shrink |> Seq.map (fun chars -> new String(List.toArray chars)) 
     } 

với điều này

static member String() = 
     { new Arbitrary<string>() with 
      override x.Generator = Gen.map (fun chars -> new String(List.toArray chars)) generate 
      override x.Shrinker s = 
       match s with 
        | null -> seq {yield null;} 
        | _ -> s.ToCharArray() |> Array.toList |> shrink |> Seq.map (fun chars -> new String(List.toArray chars)) 
     } 

Bạn có thể muốn nêu vấn đề này với các nhà phát triển fscheck here và cũng kiểm tra nếu sửa chữa của tôi hoạt động tốt - có có lẽ là một cách tốt hơn để thực hiện nó, nhưng nó sẽ đơn giản hơn cho ai đó, những người đã biết mã.

+0

Nếu đó là lỗi thì có thể gây ra sự cố nếu cố định. Vì vậy, họ có thể nâng cấp nó thành một "tính năng". – Alapago

+1

@ user2046431 Tôi rất nghi ngờ nó, vì trường hợp này sẽ thất bại và chỉ cho null 'chuỗi'. Và ngay cả khi họ quyết định nâng cấp nó lên một tính năng, ít nhất họ cũng có thể muốn theo dõi nó ở đâu đó trên trang web của họ. –

+0

Đồng ý rằng điều này nên đi đến theo dõi vấn đề của họ, và rằng sửa chữa shrinker để nó không bị nghẹt thở trên nulls sẽ không phá vỡ bất cứ điều gì. Tôi đã nghĩ đến "lỗi" không tạo ra null theo mặc định. – Alapago

1

Đối FsCheck 1.x, tôi tìm thấy một giải pháp trong đó có việc sửa đổi mặc định máy phát điện chuỗi ngẫu nhiên:

public class MyArbitraries 
{ 
    public static Arbitrary<string> String() 
    { 
     var nulls = Any.Value<string>(null); 
     var nonnulls = Arb.Default.String().Generator; 
     return Any.GeneratorIn(nulls, nonnulls).ToArbitrary; 
    } 
} 

và sau đó khởi nó với:

DefaultArbitraries.Add<MyArbitraries>(); 

Sau đó, kiểm tra trong câu hỏi không như dự định:

Spec.ForAny<string>(s => s != null).QuickCheck() // now fails, which is good 

Điều này sẽ tạo ra khoảng 50% null và 50% chuỗi ngẫu nhiên , Trọng lượng có thể được điều chỉnh:

Spec.ForAny<string>(s => true) 
    .Classify(s => s==null, "null") 
    .Classify(s => s!=null, "not null") 
    .QuickCheck(); // displays percentages 

Tuy nhiên, hiệu quả trọng phát chuỗi mặc định có thể không phải là một ý tưởng tốt nếu quyết định không bao gồm giá trị null theo mặc định là có chủ ý và không phải là một lỗi trong thư viện. Và, nếu nó là một lỗi, nó sẽ bóp méo các bản phân phối khi cố định.

+0

Tôi không gặp may mắn khi tìm thấy 'DefaultArbitraries' đâu là anh chàng đó? – Maslow

+1

Câu trả lời này chỉ áp dụng cho FsCheck 1.x. Trong 2.x bạn nên sử dụng 'Arb.register' để thay thế. Ngoài ra, trong 2.x null được tạo ra cho chuỗi. –

Các vấn đề liên quan