2008-09-18 36 views
19

Tôi đang tìm kiếm một công cụ có thể tham gia một thử nghiệm đơn vị, nhưTự động tạo lớp học từ các bài kiểm tra đơn vị?

IPerson p = new Person(); 
p.Name = "Sklivvz"; 
Assert.AreEqual("Sklivvz", p.Name); 

và tạo ra, tự động, lớp còn sơ khai tương ứng và giao diện

interface IPerson   // inferred from IPerson p = new Person(); 
{ 
    string Name 
    { 
     get;    // inferred from Assert.AreEqual("Sklivvz", p.Name); 
     set;    // inferred from p.Name = "Sklivvz"; 
    } 
} 

class Person: IPerson  // inferred from IPerson p = new Person(); 
{ 
    private string name; // inferred from p.Name = "Sklivvz"; 

    public string Name // inferred from p.Name = "Sklivvz"; 
    { 
     get 
     { 
      return name; // inferred from Assert.AreEqual("Sklivvz", p.Name); 
     } 
     set 
     { 
      name = value; // inferred from p.Name = "Sklivvz"; 
     } 
    } 

    public Person()  // inferred from IPerson p = new Person(); 
    { 
    } 
} 

Tôi biết ReSharper và Visual Studio làm một số những điều này, nhưng tôi cần một công cụ hoàn chỉnh - dòng lệnh hoặc điều gì đó - tự động đưa ra những gì cần phải làm. Nếu không có công cụ như vậy, bạn sẽ viết nó như thế nào (ví dụ: mở rộng ReSharper, từ đầu, sử dụng thư viện nào)?

+0

Bạn có thể làm điều đó với [mẫu T4.] (Http://msdn.microsoft.com/en-us/library/bb126445.aspx) Tôi không có mẫu tiện dụng, nhưng tôi có thể thử viết một, nếu bạn quan tâm. Tôi có thể thấy điều này có thể thực sự hữu ích trong việc phát triển Test-First (TDD); lừa là lấy mã của bạn để biên dịch trong khi bạn đang viết các bài kiểm tra cho các phương thức chưa tồn tại. Tất nhiên, vấn đề khác là Mẫu T4 có thể cần thông minh hơn những gì bạn đã mô tả, và tôi nghi ngờ bạn đã cung cấp một đặc điểm kỹ thuật đầy đủ trong ví dụ của bạn. –

+0

@RobertHarvey, tôi đã thảo luận điều này với một đồng nghiệp, và anh ấy ấn tượng rằng có thể có quá nhiều suy luận để thực hiện. Tôi sẽ chỉ hạnh phúc với một cái gì đó mà làm việc một cách thông minh hơn đáng kể so với hiện tại "nhấp chuột phải" điên rồ :-) – Sklivvz

Trả lời

4

Những gì bạn có vẻ cần là một trình phân tích cú pháp cho ngôn ngữ của bạn (Java) và một trình phân giải tên và loại. ("Trình tạo bảng biểu tượng").

Sau khi phân tích văn bản nguồn, trình biên dịch thường có trình phân giải tên, cố gắng ghi lại định nghĩa tên và loại tương ứng của chúng và trình kiểm tra loại, xác minh rằng mỗi biểu thức có loại hợp lệ.

Thông thường trình phân giải tên/loại than phiền khi không tìm thấy định nghĩa. Những gì bạn muốn nó làm là để tìm "không xác định" điều đó gây ra vấn đề, và suy ra một loại cho nó.

Đối

IPerson p = new Person(); 

tên resolver biết rằng "Người" và "IPerson" không được định nghĩa. Nếu đó là

Foo p = new Bar(); 

sẽ không có đầu mối nào bạn muốn có giao diện, chỉ Foo là một loại phụ huynh trừu tượng của Bar (ví dụ: một lớp hoặc giao diện). Vì vậy, quyết định đó là nó phải được biết đến với công cụ ("bất cứ khi nào bạn tìm thấy một cấu trúc như vậy, giả sử Foo là một giao diện ..."). Bạn có thể sử dụng một heuristic: IFoo và Foo có nghĩa là IFoo nên là một giao diện, và một nơi nào đó ai đó đã xác định Foo là một lớp thực hiện giao diện đó. Khi công cụ đã đưa ra quyết định này, nó sẽ cần phải cập nhật bảng biểu tượng của nó để nó có thể chuyển sang câu khác:

Đối

p.Name = "Sklivvz"; 

cho rằng p phải là một giao diện (bởi suy luận trước), sau đó Tên phải là một thành viên của trường, và nó xuất hiện loại của nó là Chuỗi từ nhiệm vụ.

Cùng với đó, báo cáo kết quả:

Assert.AreEqual("Sklivvz", p.Name); 

tên và các loại giải quyết mà không vấn đề nữa.

Nội dung của các thực thể IFoo và Foo tùy thuộc vào bạn; bạn không cần phải sử dụng và thiết lập nhưng đó là sở thích cá nhân.

này sẽ không làm việc rất tốt khi bạn có nhiều thực thể trong báo cáo kết quả giống nhau:

x = p.a + p.b ; 

Chúng ta biết a và b là khả năng lĩnh vực, nhưng bạn không thể đoán những gì loại số nếu thực sự họ số, hoặc nếu chúng là các chuỗi (điều này là hợp pháp đối với các chuỗi trong Java, dunno về C#). Đối với C++ bạn thậm chí không biết "+" có nghĩa là gì; nó có thể là một toán tử trên lớp Bar. Vì vậy, những gì bạn phải làm là thu thập các ràng buộc , ví dụ: "a là một số hoặc chuỗi không xác định", v.v và khi công cụ thu thập bằng chứng, nó thu hẹp tập hợp các ràng buộc có thể xảy ra. (Điều này hoạt động giống như những vấn đề từ đó: "Joe có bảy người con trai. Jeff cao hơn Sam. Harry không thể giấu đằng sau Sam. ... là người sinh đôi của Jeff?", Nơi bạn phải thu thập bằng chứng và loại bỏ những điều không công bằng). Bạn cũng phải lo lắng về trường hợp bạn kết thúc với một mâu thuẫn.

Bạn có thể loại trừ trường hợp p.a + p.b, nhưng sau đó bạn không thể viết các bài kiểm tra đơn vị của bạn với khả năng miễn dịch. Có những giải pháp hạn chế tiêu chuẩn ra khỏi đó nếu bạn muốn có khả năng miễn dịch. (Thật là một khái niệm).

OK, chúng tôi có ý tưởng, bây giờ, điều này có thể được thực hiện một cách thiết thực không?

Phần đầu tiên của điều này yêu cầu trình phân tích cú pháp và trình phân giải tên và loại có thể uốn cong. Bạn cần một trình giải quyết ràng buộc hoặc ít nhất là một "giá trị được xác định lưu lượng đến giá trị không xác định" hoạt động (giải quyết ràng buộc tầm thường).

DMS Software Reengineering Toolkit của chúng tôi với số Java Front End có thể có thể làm điều này. DMS là công cụ của trình xây dựng công cụ, dành cho những người muốn xây dựng các công cụ xử lý langauges máy tính theo những cách tùy ý. (Hãy suy nghĩ về "tính toán với các mảnh chương trình hơn là số").

DMS cung cấp máy phân tích mục đích chung và có thể tạo một cây cho bất kỳ giao diện người dùng nào được cung cấp (ví dụ: Java và có giao diện người dùng C#). Lý do tôi chọn Java là đầu cuối Java của chúng tôi có tất cả tên và loại máy móc phân giải, và nó được cung cấp ở dạng mã nguồn để nó có thể được uốn cong. Nếu bạn bị mắc kẹt với trình giải quyết hạn chế tầm thường, bạn có thể bẻ cong trình phân giải tên Java để tìm ra các loại. DMS sẽ cho phép bạn lắp ráp các cây tương ứng với các đoạn mã và kết hợp chúng lại thành các đoạn mã lớn hơn; khi công cụ của bạn thu thập sự kiện cho bảng biểu tượng, nó có thể xây dựng những cây nguyên thủy.

Một nơi nào đó, bạn phải quyết định bạn đã hoàn tất. Có bao nhiêu đơn vị kiểm tra công cụ phải xem trước khi nó biết toàn bộ giao diện? (Tôi đoán nó ăn tất cả những cái bạn cung cấp?). Sau khi hoàn thành, nó tập hợp các mảnh cho các thành viên khác nhau và xây dựng một AST cho một giao diện; DMS có thể sử dụng trình soạn thảo của nó để chuyển đổi AST trở lại thành mã nguồn như bạn đã hiển thị.

Tôi đề xuất Java ở đây vì giao diện người dùng Java của chúng tôi có độ phân giải tên và loại. Mặt trước C# của chúng tôi không có. Đây là một vấn đề "chỉ" của tham vọng; ai đó phải viết một, nhưng đó là khá nhiều công việc (ít nhất là cho Java và tôi không thể tưởng tượng C# là thực sự khác nhau).

Nhưng ý tưởng hoạt động tốt về nguyên tắc khi sử dụng DMS.

Bạn có thể thực hiện việc này với một số cơ sở hạ tầng khác đã cung cấp cho bạn quyền truy cập vào trình phân tích cú pháp và một trình phân giải tên và loại có thể uốn cong. Điều đó có thể không dễ dàng như vậy đối với C#; Tôi nghi ngờ MS có thể cung cấp cho bạn một trình phân tích cú pháp và truy cập vào độ phân giải tên và loại, nhưng không phải cách nào để thay đổi điều đó. Có lẽ Mono là câu trả lời?

Bạn vẫn cần một mã để tạo các đoạn mã và lắp ráp chúng. Bạn có thể cố gắng thực hiện điều này bằng cách lấy cắp chuỗi; kinh nghiệm của tôi (dài) với các bit chương trình dán với nhau là nếu bạn làm điều đó với các chuỗi bạn cuối cùng làm cho một mớ hỗn độn của nó. Bạn thực sự muốn các phần biểu diễn các đoạn mã của kiểu đã biết, chỉ có thể được kết hợp theo những cách mà ngữ pháp cho phép; DMS làm như vậy không có lộn xộn.

-2

Tôi thấy rằng bất cứ khi nào tôi cần một công cụ tạo mã như thế này, tôi có thể đang viết mã có thể được tạo thành một chút chung chung hơn vì vậy tôi chỉ cần viết nó một lần. Trong ví dụ của bạn, những getters và setters đó dường như không thêm bất kỳ giá trị nào vào mã - trên thực tế, nó thực sự chỉ khẳng định rằng cơ chế getter/setter trong C# hoạt động.

Tôi sẽ không viết (hoặc thậm chí sử dụng) một công cụ như vậy trước khi hiểu được động lực để viết các loại thử nghiệm này là gì.

BTW, bạn có thể muốn xem NBehave?

1

Nếu bạn có kế hoạch viết thực hiện của riêng mình, tôi chắc chắn sẽ đề nghị bạn hãy xem các công cụ mẫu NVelocity (C#) hoặc Velocity (Java).

Tôi đã sử dụng các trình tạo mã này trước đây và thấy rằng chúng giúp công việc dễ dàng hơn rất nhiều.

-2

Tôi sử dụng Rhino Mocks cho điều này, khi tôi chỉ cần một cuống đơn giản.

http://www.ayende.com/wiki/Rhino+Mocks+-+Stubs.ashx

+0

Đây là cách tôi làm điều đó, nói rất nhiều mã và thời gian! –

+0

Nó không tạo ra tệp ... Tôi muốn các sơ khai được tạo ra để tôi có thể sửa đổi chúng theo cách thủ công. – Sklivvz

-1

tàu Visual Studio với một số tính năng mà có thể hữu ích cho bạn ở đây:

Generate Method Stub. Khi bạn viết một cuộc gọi đến một phương thức không tồn tại, bạn sẽ nhận được một thẻ thông minh nhỏ trên tên phương thức mà bạn có thể sử dụng để tạo ra một phương thức dựa trên các tham số mà bạn đang truyền.

Nếu bạn là một người bàn phím (Tôi), sau đó ngay sau khi gõ ngoặc gần, bạn có thể làm:

  • Ctrl-. (để mở thẻ thông minh)
  • ENTER (để tạo stub)
  • F12 (đi đến định nghĩa, để đưa bạn đến các phương pháp mới)

Thẻ thông minh chỉ xuất hiện nếu IDE cho rằng không có phương thức nào phù hợp. Nếu bạn muốn tạo khi thẻ thông minh không hoạt động, bạn có thể truy cập Chỉnh sửa-> Intellisense-> Tạo phương thức Stub.

Đoạn mã. Các mẫu mã nhỏ giúp dễ dàng tạo các bit của mã phổ biến. Một số đơn giản (hãy thử "nếu [TAB] [TAB]").Một số là phức tạp ('chuyển đổi' sẽ tạo ra các trường hợp cho một enum). Bạn có thể tự viết mà. Trong trường hợp của bạn, hãy thử "class" và "prop".

Xem thêm "How to change “Generate Method Stub” to throw NotImplementedException in VS?" cho đoạn trích thông tin trong ngữ cảnh của GMS.

autoprops. Hãy nhớ rằng các thuộc tính có thể đơn giản hơn nhiều:

public string Name { get; set; } 

tạo lớp. Trong Solution Explorer, RClick trên tên dự án hoặc thư mục con, chọn Add-> Class. Nhập tên của lớp mới của bạn. Nhấn ENTER. Bạn sẽ nhận được tuyên bố lớp học ở đúng không gian tên, v.v.

Giao diện triển khai. Khi bạn muốn một lớp để thực hiện một giao diện, hãy viết một phần tên giao diện, kích hoạt thẻ thông minh, và chọn một trong hai tùy chọn để tạo ra các nhánh cho các thành viên giao diện.

Đây không phải là giải pháp tự động hoàn toàn 100% mà bạn đang tìm kiếm, nhưng tôi nghĩ đó là một biện pháp giảm thiểu tốt.

+0

Cảm ơn, tôi đã sử dụng những công cụ đó, nhưng điều tôi quan tâm là phức tạp hơn, ví dụ như suy luận từ bài tập và khẳng định rằng tài sản được đọc viết – Sklivvz

0

Tôi thích CodeRush từ DevExpress. Họ có một công cụ tạo khuôn mẫu tùy biến rất lớn. Và điều tốt nhất cho tôi là không có hộp thoại. Chúng cũng có chức năng tạo các phương thức và các giao diện và các lớp từ giao diện không tồn tại.

3

Điều tuyệt vời của nó như thế nào không ai thực sự đưa ra bất cứ điều gì đối với những gì bạn đang yêu cầu.

Tôi không biết câu trả lời, nhưng tôi sẽ suy nghĩ về nó.

Nếu tôi cố gắng viết một cái gì đó như thế này bản thân tôi có thể sẽ thấy về một plugin resharper. Lý do tôi nói đó là bởi vì như bạn đã nói, resharper có thể làm điều đó, nhưng trong từng bước. Vì vậy, tôi sẽ viết một cái gì đó mà đã đi từng dòng và áp dụng các phương pháp tạo resharper thích hợp xích lại với nhau.

Bây giờ không có nghĩa là tôi thậm chí biết làm thế nào để làm điều này, như tôi chưa bao giờ xây dựng bất cứ điều gì để resharper, nhưng đó là những gì tôi sẽ cố gắng làm. Nó có ý nghĩa logic rằng nó có thể được thực hiện.

Và nếu bạn viết lên một số mã, XIN VUI LÒNG gửi nó, vì tôi có thể thấy rằng hữu ích là tốt, có thể tạo ra toàn bộ bộ xương trong một bước. Rất hữu dụng.

1

Có thể thực hiện được - ít nhất theo lý thuyết. Những gì tôi sẽ làm là sử dụng một cái gì đó như csparser để phân tích các bài kiểm tra đơn vị (bạn không thể biên dịch nó, không may) và sau đó mang nó từ đó. Vấn đề duy nhất tôi có thể thấy là những gì bạn đang làm là sai về phương pháp luận - nó có ý nghĩa hơn để tạo ra các bài kiểm tra đơn vị từ các lớp thực thể (thực sự, Visual Studio thực hiện chính xác điều này) hơn là làm theo cách khác.

+0

Nó không phải là phương pháp sai, chỉ khác nhau. TDD là cơ sở phát triển. – MrJames

+0

@DmitriNesteruk Tôi vừa đọc qua một số tài liệu về trình chỉnh sửa plugin resharper của bạn ... bạn nghĩ khó khăn thế nào khi tạo plugin để thực hiện việc này? Như OP nói, nó đã làm hầu hết những gì anh ta cần, nó chỉ cần một số tính năng hiện có bao bọc thành một hành động duy nhất. – Robbie

+0

@Robbie ReSharper đã thực hiện rất nhiều điều này thông qua 'tạo từ việc sử dụng'. Nếu bạn cần nó bán buôn, bạn có thể tự động hóa các hành động R # hiện có để thực hiện nhiều thay đổi cùng một lúc và phần * này * có thể là một chút khó khăn. –

0

Hãy thử nhìn vào Pex, Một dự án microsoft trên kiểm tra đơn vị, mà vẫn còn đang được nghiên cứu

research.microsoft.com/en-us/projects/Pex/

0

Tôi nghĩ rằng những gì bạn đang tìm kiếm là một bộ công cụ mờ (https://en.wikipedia.org/wiki/Fuzz_testing).

Al khó khăn tôi không bao giờ được sử dụng, bạn có thể cung cấp cho Randoop.NET một cơ hội để tạo ra 'đơn vị kiểm tra' http://randoop.codeplex.com/

1

Tôi nghĩ rằng một giải pháp thực tế cho vấn đề này sẽ là một phân tích cú pháp rất đặc biệt. Vì đó không phải là dễ dàng như vậy, tôi có một ý tưởng rẻ hơn. Thật không may, bạn phải thay đổi cách bạn viết các bài kiểm tra của mình (cụ thể là, chỉ việc tạo đối tượng):

dynamic p = someFactory.Create("MyNamespace.Person"); 
p.Name = "Sklivvz"; 
Assert.AreEqual("Sklivvz", p.Name); 

Một đối tượng nhà máy sẽ được sử dụng. Nếu nó có thể tìm thấy đối tượng được đặt tên, nó sẽ tạo ra nó và trả về nó (đây là thực thi kiểm tra bình thường). Nếu nó không tìm thấy nó, nó sẽ tạo ra một proxy ghi âm (một DynamicObject) sẽ ghi lại tất cả các cuộc gọi và cuối cùng (có thể trên xé xuống) có thể phát ra các tập tin lớp (có thể dựa trên một số mẫu) phản ánh những gì nó "thấy " được gọi là.

Một số nhược điểm mà tôi thấy:

  • Cần để chạy mã trong "hai" chế độ, đó là gây phiền nhiễu.
  • Để proxy ủy quyền "xem" và ghi lại cuộc gọi, chúng phải được thực hiện; do đó, mã trong một khối catch, ví dụ, phải chạy.
  • Bạn phải thay đổi cách bạn tạo đối tượng đang được thử nghiệm.
  • Bạn phải sử dụng dynamic; bạn sẽ mất an toàn thời gian biên dịch trong các lần chạy tiếp theo và nó có hiệu suất cao.

Lợi thế duy nhất tôi thấy là nó là rẻ hơn rất nhiều để tạo hơn một trình phân tích cú pháp chuyên biệt.

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