2011-08-16 14 views
5

Tôi có chữ ký phương thức này: List<ITMData> Parse(string[] lines)Làm cách nào để kiểm tra hiệu quả trình phân tích cú pháp tệp phẳng có độ dài cố định bằng MSpec?

ITMData có 35 thuộc tính.

Làm thế nào để bạn hiệu quả kiểm tra trình phân tích cú pháp này?

Câu hỏi:

  • Tôi có nên tải toàn bộ tập tin (Tôi có thể sử dụng System.IO)?
  • Tôi có nên đặt một dòng từ tệp vào hằng số chuỗi không?
  • Tôi có nên kiểm tra một hoặc nhiều dòng
  • Tôi có nên kiểm tra từng thuộc tính của ITMData hoặc tôi có nên thử nghiệm toàn bộ đối tượng không?
  • Còn việc đặt tên cho thử nghiệm của tôi thì sao?

EDIT

Tôi đã thay đổi chữ ký phương pháp để ITMData Parse(string line).

Mã kiểm tra:

[Subject(typeof(ITMFileParser))] 
public class When_parsing_from_index_59_to_79 
{ 
    private const string Line = "........."; 
    private static ITMFileParser _parser; 
    private static ITMData _data; 

    private Establish context =() => { _parser = new ITMFileParser(); }; 

    private Because of =() => { _data = _parser.Parse(Line); }; 

    private It should_get_fldName =() => _data.FldName.ShouldBeEqualIgnoringCase("HUMMELDUMM"); 
} 

EDIT 2

Tôi vẫn không chắc chắn nếu tôi nên kiểm tra chỉ một tài sản mỗi lớp. Theo ý kiến ​​của tôi, điều này cho phép tôi cung cấp thêm thông tin cho đặc điểm kỹ thuật cụ thể là khi tôi phân tích cú pháp một dòng từ chỉ mục 59 thành chỉ mục 79, tôi lấy fldName. Nếu tôi kiểm tra tất cả các thuộc tính trong một lớp I mất thông tin này. Tôi có vượt qua các bài kiểm tra của mình không?

Các xét nghiệm của tôi bây giờ trông như thế này:

[Subject(typeof(ITMFileParser))] 
public class When_parsing_single_line_from_ITM_file 
{ 
    const string Line = "" 

    static ITMFileParser _parser; 
    static ITMData _data; 

    Establish context =() => { _parser = new ITMFileParser(); }; 

    private Because of =() => { _data = _parser.Parse(Line); }; 

    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    It should_get_fld??? =() => _data.Fld???.ShouldEqual(???); 
    ... 

} 
+0

Ý anh là gì bởi "hiệu quả" chính xác? Bạn có muốn giảm thiểu thời gian phát triển của các bài kiểm tra đơn vị không? –

+0

cũng có nghĩa là thử nghiệm với một chuỗi hoặc với nhiều chuỗi? thử nghiệm với một chuỗi chỉ chứa các giá trị tôi muốn khẳng định hoặc lấy toàn bộ chuỗi. – Rookian

+0

Tôi vẫn chưa chắc chắn 100% chính xác câu hỏi là gì, nhưng tôi sẽ tạo ra một tập hợp các bài kiểm tra đơn vị khác nhau. Một phương pháp thử nghiệm có thể vượt qua trong một chuỗi đơn cụ thể và khẳng định rằng nó đã được phân tích cú pháp chính xác vào các thuộc tính có liên quan trên đối tượng IMTData kết quả. Có lẽ một thử nghiệm khác để kiểm tra 20 dòng, nó tạo ra một danh sách 20 mục. Tôi có thể có các phương pháp khác cho các trường hợp khó khăn cụ thể. Đây là khá nhiều những gì @Kenny đã mô tả, công cụ thử nghiệm đơn vị cơ bản. Lấy các yêu cầu cho phương thức Parse này, và đảo ngược kỹ thuật nó thành một vài trường hợp kiểm tra chứng minh tính chính xác. –

Trả lời

2

Đây là những gì tôi thường sẽ làm gì nếu tôi đang phải đối mặt với một vấn đề như vậy:

Một chối ngắn trước: Tôi nghĩ rằng tôi hơn sẽ đi xuống "thử nghiệm tích hợp" hoặc "thử nghiệm phân tích cú pháp như một tổng thể" tuyến đường thay vì thử nghiệm các tuyến riêng lẻ. Trong quá khứ tôi đã từng đối mặt với tình huống mà nhiều chi tiết thực hiện bị rò rỉ vào các thử nghiệm của tôi và buộc tôi phải thay đổi các bài kiểm tra thường xuyên khi tôi thay đổi các chi tiết thực hiện. Trường hợp điển hình của overspecification tôi đoán; -/

  1. Tôi sẽ không bao gồm việc tải tệp trong trình phân tích cú pháp. Như @mquander đề nghị tôi thà đi với một TextReader hoặc một IEnumerable làm tham số đầu vào để thay thế. Điều này sẽ dẫn đến việc kiểm tra nhanh hơn vì bạn có thể chỉ định đầu vào của trình phân tích cú pháp trong bộ nhớ và không phải chạm vào hệ thống tệp.
  2. Tôi không phải là một fan hâm mộ lớn của dữ liệu kiểm tra cán tay, vì vậy trong hầu hết các trường hợp, tôi đang sử dụng tài nguyên nhúng và ResourceManager để tải dữ liệu kiểm tra trực tiếp từ hội đồng đặc điểm kỹ thuật thông qua assembly.GetManifestResource(). Tôi thường có một loạt các phương pháp mở rộng trong giải pháp của mình để sắp xếp hợp lý việc đọc tài nguyên (giống như TextReader TextResource.Load ("NAME_OF_SOME_RESOURCE")).
  3. Về MSpec: Tôi đang sử dụng một lớp cho mỗi tệp để phân tích cú pháp. Đối với mỗi thuộc tính được kiểm tra trong kết quả phân tích cú pháp, tôi có xác nhận riêng biệt (It). Đây thường là một lớp lót, vì vậy số lượng mã hóa bổ sung không lớn như vậy.Về tài liệu và chẩn đoán, đó là một điểm cộng lớn vì khi một thuộc tính không được phân tích cú pháp một cách chính xác, bạn có thể thấy trực tiếp xác nhận nào không thành công mà không phải xem xét nguồn hoặc tìm kiếm số dòng. Nó cũng xuất hiện trong tệp kết quả MSpec của bạn. Bên cạnh đó, bạn không ẩn các xác nhận không thành công khác (trường hợp bạn sửa một xác nhận chỉ để xem thông số thất bại trên dòng tiếp theo với xác nhận tiếp theo). Điều này tất nhiên buộc bạn phải suy nghĩ nhiều hơn về từ ngữ bạn sử dụng trong thông số kỹ thuật của bạn nhưng đối với tôi đó cũng là một điểm cộng lớn vì tôi là người đề xuất ý tưởng rằng các hình thức ngôn ngữ suy nghĩ. Nói cách khác, nếu bạn không có đầu mối làm thế nào để frackin tên xác nhận của bạn có lẽ một cái gì đó fishy hoặc về đặc điểm kỹ thuật của bạn hoặc thực hiện của bạn.
  4. Về chữ ký phương pháp của bạn cho trình phân tích cú pháp: Tôi sẽ không trả lại loại bê tông như Danh sách <T> hoặc mảng và tôi cũng khuyên bạn không nên trả lại loại có thể biến đổi <T>. Những gì bạn đang nói về cơ bản ở đây là: "Này, bạn có thể muck xung quanh với kết quả phân tích cú pháp sau khi tôi đã hoàn thành" mà trong nhiều trường hợp có lẽ là những gì bạn không muốn. Tôi sẽ đề nghị trở lại IEnumerable <T> thay vì (hoặc ICollection <T> nếu bạn thực sự cần phải sửa đổi nó sau này)
+0

cảm ơn cho đến nay :) 1. Tôi phân tích một dòng đơn, bởi vì mỗi dòng được phân tích cú pháp theo cùng một cách 2. Tôi sẽ lo lắng về việc đưa dữ liệu thử nghiệm của tôi vào tài nguyên. 3. Tôi không thể sử dụng một lớp cho mỗi loại tệp, vì có một số logic đặc biệt phụ thuộc vào cấu hình. Vì vậy, một số thuộc tính phải được kiểm tra riêng biệt. 4. Tôi chọn để phân tích cú pháp chỉ một dòng duy nhất. – Rookian

1

tôi thường cố gắng xem xét sự thành công chung và không kịch bản, cùng với các trường hợp cạnh. Yêu cầu cũng hữu ích cho việc thiết lập các trường hợp sử dụng thích hợp. Xem xét Pex để liệt kê các tình huống khác nhau.

4

Tôi có nên tải toàn bộ tệp (Tôi có thể sử dụng System.IO) không?

Nếu bạn làm điều này, nó không còn là phép thử đơn vị - nó trở thành thử nghiệm tích hợp hoặc hồi quy. Bạn có thể làm điều này, nếu bạn mong đợi nó hiển thị các lỗi có thể xảy ra mà một thử nghiệm đơn vị sẽ không. Nhưng đó không phải là quá khả năng.

Có lẽ bạn nên sử dụng các bài kiểm tra đơn vị, ít nhất là để bắt đầu.

Tôi có nên đặt một dòng từ tệp vào hằng số chuỗi không?

Nếu bạn dự định viết nhiều hơn một bài kiểm tra sử dụng cùng một dòng nhập, thì chắc chắn. Nhưng cá nhân, tôi có lẽ sẽ có xu hướng viết một loạt các bài kiểm tra khác nhau, với mỗi người đi qua một chuỗi đầu vào khác nhau. Tại thời điểm đó, không có nhiều lý do để tạo một hằng số (trừ khi đó là một hằng số cục bộ, được khai báo bên trong phương thức thử nghiệm).

Tôi có nên kiểm tra một hoặc nhiều dòng không?

Bạn không nói rõ, nhưng tôi sẽ cho rằng đầu ra của bạn là một-cho-một với đầu vào của bạn - có nghĩa là, nếu bạn vượt qua trong ba chuỗi, bạn sẽ nhận được ba ITMData s trả lại. Trong trường hợp đó, nhu cầu kiểm tra nhiều dòng sẽ bị hạn chế.

Nó gần như luôn luôn có giá trị thử nghiệm trường hợp thoái hóa, mà trong trường hợp này sẽ là một mảng chuỗi rỗng (zero dòng). Và có thể có ít nhất một bài kiểm tra có nhiều hơn một dòng, chỉ để bạn có thể đảm bảo không có sai lầm ngớ ngẩn trong lần lặp lại của mình.

Tuy nhiên, nếu đầu ra của bạn là một-với-một với đầu vào của bạn, thì bạn thực sự có một phương pháp khác muốn thoát ra - bạn cần có phương thức ParseSingleLine. Sau đó, Parse của bạn sẽ không có gì khác ngoài việc lặp lại các dòng và gọi số ParseSingleLine. Bạn vẫn muốn một số ít các bài kiểm tra cho Parse, nhưng hầu hết các bài kiểm tra của bạn sẽ tập trung xung quanh ParseSingleLine.

+0

Tôi đã chỉnh sửa câu hỏi của mình. cảm ơn cho đến nay. – Rookian

0

Về câu hỏi mới hơn của bạn:

Tôi có nên kiểm tra mỗi tài sản của ITMData hay tôi nên kiểm tra toàn bộ đối tượng?

Nếu bạn muốn ở bên an toàn, có thể bạn nên có ít nhất một thử nghiệm kiểm tra xem mỗi thuộc tính đã được khớp.

Còn việc đặt tên cho thử nghiệm của tôi thì sao?

Có một số cuộc thảo luận về chủ đề này, chẳng hạn như this one. Quy tắc chung là bạn sẽ có nhiều phương thức trong lớp thử nghiệm đơn vị của bạn, mỗi phương pháp nhằm mục đích thử nghiệm một cái gì đó cụ thể. Trong trường hợp của bạn, nó có thể là những thứ như:

public void Check_All_Properties_Parsed_Correctly(){.....} 

public void Exception_Thrown_If_Lines_Is_Null(){.....} 

public void Exception_Thrown_If_Lines_Is_Wrong_Length(){.....} 

Vì vậy, nói cách khác, kiểm tra hành vi chính xác mà bạn cho là "đúng" cho trình phân tích cú pháp. Một khi điều này được thực hiện, bạn sẽ cảm thấy thoải mái hơn nhiều khi thực hiện các thay đổi đối với mã trình phân tích cú pháp, bởi vì bạn sẽ có một bộ kiểm thử toàn diện để kiểm tra xem bạn đã không phá vỡ bất cứ điều gì. Hãy nhớ thực sự kiểm tra thường xuyên, và để giữ cho các bài kiểm tra của bạn được cập nhật khi bạn thực hiện thay đổi! Có một hướng dẫn khá tốt về thử nghiệm đơn vị và Phát triển theo hướng thử nghiệm trên MSDN.

Nói chung, tôi nghĩ bạn có thể tìm thấy câu trả lời cho hầu hết các câu hỏi của mình bằng cách googling một chút. Ngoài ra còn có một số cuốn sách tuyệt vời về Phát triển theo hướng thử nghiệm, sẽ hướng về nhà không chỉ cách của TDD, mà là lý do tại sao. Nếu bạn là ngôn ngữ lập trình tương đối thuyết bất khả tri, tôi sẽ giới thiệu Kent Beck's Test Driven Development By Example, nếu không một cái gì đó như Test-Driven Development in Microsoft .NET. Chúng sẽ giúp bạn đi đúng hướng rất nhanh.

EDIT:

Am Tôi overspecifying thử nghiệm của tôi?

Theo ý kiến ​​của tôi, có. Cụ thể, tôi không đồng ý với dòng tiếp theo của bạn:

Nếu tôi kiểm tra tất cả các thuộc tính trong một lớp, tôi sẽ mất thông tin này.

Bạn mất thông tin chính xác theo cách nào? Hãy nói rằng có 2 cách để làm thử nghiệm này, ngoại trừ việc có một lớp mới cho mỗi bài kiểm tra:

  1. Có khác nhau phương pháp cho mỗi thuộc tính. Phương pháp thử nghiệm của bạn có thể được gọi là CheckPropertyX, CheckPropertyY, v.v. Khi bạn chạy thử nghiệm, bạn sẽ thấy chính xác trường nào được chuyển và trường nào không thành công. Điều này rõ ràng đáp ứng yêu cầu của bạn, mặc dù tôi sẽ nói rằng nó vẫn còn quá mức cần thiết. Tôi sẽ đi với tùy chọn 2:
  2. Có một vài phương pháp khác nhau, mỗi phương pháp thử nghiệm một khía cạnh cụ thể. Đây là những gì tôi ban đầu được đề nghị, và tôi nghĩ rằng những gì bạn đang đề cập đến. Khi một trong các bài kiểm tra thất bại, bạn sẽ chỉ nhận được thông tin về điều đầu tiên không thành công, theo phương pháp, nhưng nếu bạn mã hóa Assert của mình một cách độc đáo, bạn sẽ biết chính xác thuộc tính nào. Xét đoạn mã sau:

Assert.AreEqual("test1", myObject.PropertyX, "Property X was incorrectly parsed"); Assert.AreEqual("test2", myObject.PropertyY, "Property Y was incorrectly parsed");

Khi một trong những thất bại, bạn sẽ biết được dòng thất bại. Khi bạn đã khắc phục lỗi có liên quan và chạy lại các thử nghiệm của mình, bạn sẽ thấy nếu bất kỳ thuộc tính nào khác không thành công. Đây thường là cách tiếp cận mà hầu hết mọi người thực hiện, bởi vì việc tạo một lớp hoặc thậm chí phương thức cho mỗi thuộc tính dẫn đến quá nhiều mã và quá nhiều công việc để cập nhật.

+0

Tôi đã chỉnh sửa lại câu hỏi của mình. – Rookian

+0

OK, tôi đã trả lời chỉnh sửa của bạn, đề xuất của tôi sẽ tối đa là tạo phương thức mới cho mỗi thuộc tính, để kiểm tra thuộc tính đó. –

+0

"Theo cách nào bạn mất thông tin chính xác?" Machine.Specification cho phép tạo báo cáo HTML. Như bạn có thể thấy các bài kiểm tra của tôi bắt đầu bằng "Khi _..." Vì vậy, tên lớp là một phần của đặc tả. Nếu tôi viết một lớp cho mỗi thuộc tính, tôi sẽ có một đặc tả cụ thể có chứa chỉ mục nào được sử dụng để lấy một thuộc tính cụ thể. – Rookian

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