2013-06-01 30 views
25

Tôi đã thử đơn vị kiểm tra một phương pháp trong một trong các Bộ điều khiển của tôi trả về một JsonResult. Trước sự ngạc nhiên của tôi đoạn mã sau không làm việc:Xác nhận JsonResult Có chứa Loại Chưa xác định

[HttpPost] 
public JsonResult Test() { 
    return Json(new {Id = 123}); 
} 

Đây là cách tôi thử nghiệm nó (cũng lưu ý rằng mã kiểm tra nằm trong lắp ráp khác):

// Act 
dynamic jsonResult = testController.Test().Data; 

// Assert 
Assert.AreEqual(123, jsonResult.Id); 

Các Assert ném một ngoại lệ:

'đối tượng' không chứa một định nghĩa cho 'Id'

Tôi đã giải quyết vấn đề này bằng cách sử dụng các mục sau:

[HttpPost] 
public JsonResult Test() { 
    dynamic data = new ExpandoObject(); 
    data.Id = 123; 
    return Json(data); 
} 

Tôi đang cố gắng hiểu tại sao người đầu tiên không làm việc? Nó cũng có vẻ là làm việc với cơ bản bất cứ điều gì NHƯNG một loại vô danh.

+1

Tôi đã thử mã của bạn bằng loại ẩn danh và nó hoạt động tốt cho tôi. Không chắc chắn lý do bạn nhận được lỗi đó. –

+0

Bạn nhận được gì khi in ra 'jsonResult.GetType()'? (lỗi cho biết nó nghĩ rằng nó thuộc loại 'đối tượng' thay vì loại' <> f__AnonymousType0', đó là những gì tôi mong đợi) –

+0

Kiểu là đối tượng thực sự. Tôi mong nó sẽ tự làm việc, không chắc tại sao tôi lại nhận được những kết quả đó. –

Trả lời

29

Để rõ ràng, vấn đề cụ thể bạn đang gặp phải là C# động không hoạt động với các thành viên ngoài công lập. Điều này là do thiết kế, có lẽ là để ngăn cản điều đó. Vì như LukLed đã nói, các kiểu ẩn danh chỉ được công khai trong cùng một assembly (hoặc chính xác hơn, các kiểu vô danh đơn giản được đánh dấu internal, chứ không phải là public), bạn đang chạy vào rào cản này.

Có lẽ giải pháp sạch sẽ nhất là để bạn sử dụng InternalsVisibleTo. Nó cho phép bạn đặt tên cho một hội đồng khác có thể truy cập các thành viên ngoài công lập của nó. Sử dụng nó để kiểm tra là một trong những lý do chính cho sự tồn tại của nó. Trong ví dụ của bạn, bạn sẽ đặt trong AssemblyInfo.cs của dự án chính của mình theo dòng sau:

[assembly: InternalsVisibleTo("AssemblyNameOfYourTestProject")] 

Khi bạn làm điều đó, lỗi sẽ biến mất (tôi vừa thử nó).

Ngoài ra, bạn có thể chỉ cần sử dụng brute force phản ánh:

Assert.AreEqual(123, jsonResult.GetType().GetProperty("Id").GetValue(jsonResult, null)); 
+0

Bạn có thể giải thích tùy chọn cuối cùng không? – Ani

+0

Bạn có thể làm rõ câu hỏi của mình không? Bạn có tự hỏi về sự phản chiếu nói chung hay cái gì đó về cách nó áp dụng cho câu hỏi/câu trả lời này? –

+0

phản ánh nói chung – Ani

4

Các loại ẩn danh là nội bộ, vì vậy bạn không thể hiển thị chúng ở thư viện khác, thư viện có các bài kiểm tra. Nếu bạn đặt mã thử nghiệm trong cùng một thư viện với bộ điều khiển, nó sẽ hoạt động.

+0

Tôi không biết, cảm ơn rất nhiều. Tôi đánh giá cao câu trả lời của bạn. –

+1

Bạn cũng có thể tuyên bố lắp ráp thử nghiệm một "hội đồng bạn bè" để phơi bày internals. http://msdn.microsoft.com/en-us/library/0tke9fxk(v=vs.80).aspx –

10

Sau khi đọc các câu trả lời ở đây và sau đó nhìn xa hơn tôi tìm thấy một 2009 msdn blog post với một cách tiếp cận khác nhau một lần nữa. Nhưng .. trong các ý kiến ​​là một giải pháp rất đơn giản và rất thanh lịch bởi Kieran ... để sử dụng .ToString().

Trong trường hợp ban đầu của bạn:

[HttpPost] 
public JsonResult Test() 
{ 
    return Json(new {Id = 123}); 
} 

Bạn có thể kiểm tra bằng cách thực hiện:

var jsonResult = controller.Test(); 
Assert.AreEqual("{Id = 123}", jsonResult.Data.ToString()); 

Tôi rất thích giải pháp này vì nó:

  • tránh thay đổi mã gốc (InternalsVisibleTo , ExpandoObject),
  • tránh sử dụng MvcContribRhinoMocks (không có vấn đề với một trong những lý do tại sao nhưng thêm chỉ để có thể kiểm tra JsonResult?), Và,
  • tránh sử dụng Reflection (thêm phức tạp cho các bài kiểm tra).
Các vấn đề liên quan