Câu hỏi này liên quan đến kỹ thuật kiểm tra đơn vị chung với một loạt các trường hợp có khả năng rất hữu ích. Nhưng dễ hiểu hơn với ví dụ minh họa câu hỏi của tôi tốt hơn.Việc xác định TestMethod có trong các lớp cơ sở thử nghiệm không được hỗ trợ bởi MsTest?
Giả sử tôi muốn kiểm tra tất cả các loại ghi đè Equals()
sẽ thực hiện chính xác như vậy. Kể từ Equals()
được định nghĩa là ảo trong System.Object
, một loạt các loại có thể thay đổi hành vi đó. Mỗi loại làm như vậy, sẽ phải có các bài kiểm tra để đảm bảo rằng hành vi mới tuân theo các kỳ vọng tiềm ẩn của người gọi của phương thức đó. Cụ thể cho Equals()
, nếu bạn ghi đè phương pháp đó, triển khai mới phải đảm bảo rằng hai đối tượng bằng nhau cũng có mã băm bằng nhau, như được xác định bởi System.Object.GetHashCode()
.
Vì vậy, để thực thi điều này, nhiều lớp thử nghiệm sẽ là cần thiết và tất cả chúng sẽ kiểm tra tính nhất quán của hành vi trên tất cả các loại này.
Để tránh phải gõ lại tất cả các TestMethods cần thiết để kiểm tra như một loại I thay vì định nghĩa một lớp thử nghiệm cơ bản trông giống như dưới đây, và có những lớp học thử nghiệm tất cả các thừa kế cùng bộ kiểm tra hành vi:
/// <summary>
/// Test fixture base class for testing types that overrides Object.Equals()
/// </summary>
/// <typeparam name="T">The production type under test</typeparam>
public abstract class EqualsFixtureBase<T>
{
#region Equals tests
protected static void CompareInstances(T inst1, T inst2, bool expectedEquals)
{
Assert.AreEqual(expectedEquals, inst1.Equals((T)inst2));
Assert.AreEqual(expectedEquals, inst1.Equals((object)inst2));
if (expectedEquals)
{
// equal instances MUST have identical hash codes
// this is a part of the .NET Equals contract
Assert.AreEqual(inst1.GetHashCode(), inst2.GetHashCode());
}
else
{
if (inst2 != null)
{
Assert.AreNotEqual(inst1.GetHashCode(), inst2.GetHashCode());
}
}
}
/// <summary>
/// Creates version 1 instance of the type under test, not 'Equal' to instance 2.
/// </summary>
/// <returns>An instance created with properties 1.</returns>
protected abstract T CreateInstance1();
/// <summary>
/// Creates version 2 instance of the type under test, not 'Equal' to instance 1.
/// </summary>
/// <returns>An instance created with properties 2.</returns>
protected abstract T CreateInstance2();
/// <summary>
/// Creates an instance equal to the version 1 instance, but not the identical
/// same object.
/// </summary>
/// <returns>An instance created with properties equal to instance 1.</returns>
protected abstract T CreateInstanceThatEqualsInstance1();
[TestMethod]
public void Equals_NullOrDefaultValueTypeInstance()
{
T instance = CreateInstance1();
CompareInstances(instance, default(T), false);
}
[TestMethod]
public void Equals_InstanceOfAnotherType()
{
T instance = CreateInstance1();
Assert.IsFalse(instance.Equals(new object()));
}
[TestMethod]
public void Equals_SameInstance()
{
T slot1 = CreateInstance1();
CompareInstances(slot1, slot1, true);
}
[TestMethod]
public void Equals_EqualInstances()
{
T slot1 = CreateInstance1();
T slot2 = CreateInstanceThatEqualsInstance1();
CompareInstances(slot1, slot2, true);
CompareInstances(slot2, slot1, true);
}
[TestMethod]
public void Equals_NonEqualInstances()
{
T slot1 = CreateInstance1();
T slot2 = CreateInstance2();
CompareInstances(slot1, slot2, false);
CompareInstances(slot2, slot1, false);
}
#endregion Equals tests
}
Sau đó tôi có thể sử dụng lại các TestMethods này cho mỗi loại ghi đè Equals(). Ví dụ, đây sẽ là định nghĩa lớp thử nghiệm để kiểm tra rằng các loại System.String
thực hiện Equals()
chính xác.
[TestClass]
public class ExampleOfAnEqualsTestFixture : EqualsFixtureBase<string>
{
[TestMethod]
public void Foo()
{
Assert.IsTrue(true);
}
protected override string CreateInstance1()
{
return "FirstString";
}
protected override string CreateInstance2()
{
return "SecondString";
}
protected override string CreateInstanceThatEqualsInstance1()
{
return "FirstString";
}
}
Điều này cũng có thể được mở rộng thêm. Ví dụ, đối với các kiểu quá tải các toán tử == và! =, Lớp cơ sở thử nghiệm trừu tượng thứ hai có thể được định nghĩa (ví dụ EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>
) để kiểm tra việc thực hiện các toán tử đó không chỉ đúng, mà còn phù hợp với định nghĩa mở rộng của Equals()
và GetHashCode()
.
Tôi có thể làm điều này bằng cách sử dụng NUnit, nhưng khi sử dụng MsTest tôi gặp sự cố.
a) Visual Studio 2010 chỉ phát hiện ra phương pháp thử nghiệm Foo()
, không phải phương pháp thử nghiệm kế thừa để không thể chạy chúng. Dường như bộ tải thử nghiệm Visual Studio không đi theo hệ thống phân cấp thừa kế của lớp thử nghiệm.
b) Khi tôi kiểm tra các loại này trong TFS, TFS tìm loại EqualsFixtureBase trừu tượng và cho rằng đó là một lớp thử nghiệm sẽ được chạy. Nhưng vì nó không thể được tạo ra, nó không thể chạy nó và nhãn các bài kiểm tra trong loại đó là không xác định - mà không chạy thử nghiệm, và do đó xây dựng (!).
Có cách nào để giải quyết vấn đề này hay đây là hạn chế của MsTest và Visual Studio?
Nếu có, hãy sửa lỗi này trong lộ trình cho VS/TFS ?? Điều này sẽ rất hữu ích, đặc biệt là khi thử nghiệm các loại sản xuất thực hiện một giao diện, hoặc là một phần của một băng giá thừa kế, nơi các thành viên nhất định có thuộc tính 'hợp đồng loại' hoặc bất biến - nếu điều đó có ý nghĩa.
Về cơ bản, không có hỗ trợ cho điều này ngăn cản tôi từ việc tái cấu trúc mã thử nghiệm của tôi để xóa trùng lặp.
Cảm ơn
EDIT: Tôi tìm thấy this link đến một trong những blog MSDN, nó nói như sau
"Trong Whidbey, hỗ trợ cho các lớp học thử nghiệm thừa kế đã mất tích trong NUnit, nó được hỗ trợ đầy đủ. Điều này sẽ được sửa chữa ở Orcas. "
Điều đó đã được viết hơn ba năm trước. Tại sao điều này chưa được thêm vào? Tôi không hiểu, có lý do chính đáng để có điều này và trong tâm trí của tôi nó sẽ là một thay đổi nhỏ. Hay tôi chỉ không nhảy đúng vòng ở đây?
@ Jack & Rory: Giai đoạn tiền thưởng kết thúc trong khi câu hỏi này vẫn chưa được giải quyết, vì vậy tôi sẽ không đánh dấu câu hỏi này là đã trả lời. Tuy nhiên bạn đã đóng góp tốt và cả hai phần đã giúp, vì vậy tôi đã bỏ phiếu cho mỗi câu trả lời tương ứng của bạn một khe. Nếu tôi hiểu các quy tắc một cách chính xác, điều này có nghĩa là bạn sẽ chia sẻ các điểm thưởng. – Mahol25