Dọn dẹp & Sắp xếp thực hành trong quá trình thử nghiệm tích hợp để tránh cơ sở dữ liệu bẩn


9

Tôi đang kiểm tra mã hóa trong C # và tôi đã giải quyết với cấu trúc này:

try
{
    // ==========
    // ARRANGE
    // ==========

    // Insert into the database all test data I'll need during the test

    // ==========
    // ACT
    // ==========

    // Do what needs to be tested

    // ==========
    // ASSERT
    // ==========

    // Check for correct behavior
}
finally
{
    // ==========
    // CLEANUP
    // ==========

    // Inverse of ARRANGE, delete the test data inserted during this test
}

Khái niệm này là "mọi thử nghiệm sẽ dọn sạch mớ hỗn độn mà nó tạo ra". Tuy nhiên, một số thử nghiệm đang để lại cơ sở dữ liệu bẩn và các thử nghiệm thất bại sau đó.

Cách đúng đắn để làm điều này là gì? (giảm thiểu lỗi, giảm thiểu thời gian chạy)

  • Deletes everything» Insert defaults» Insert test data»Chạy thử?
  • Insert defaults» Insert test data» Chạy thử » Delete everything?

  • Hiện tại :

    • (mỗi phiên) Deletes everything»Insert defaults
    • (mỗi bài kiểm tra) Insert test data»Chạy thử»Delete test data

Câu trả lời:


7

Bên cạnh thực tế rằng đây là một thử nghiệm tích hợp trái ngược với thử nghiệm đơn vị, các hoạt động bạn mô tả thường đi vào Setupvà / hoặc Teardownphương thức. Các khung như nUnit cho phép một người trang trí các phương thức lớp với các thuộc tính này để cho biết phương thức đó là phương thức thiết lập hay phương thức phá bỏ.

Sau đó, các thử nghiệm của bạn sẽ trở nên sạch hơn và nhỏ hơn vì việc thiết lập và dọn dẹp được thực hiện bên ngoài thử nghiệm.

Nhiều khả năng nhiều bài kiểm tra có thể sử dụng lại cùng một dữ liệu để đó là điểm cộng cũng như trái ngược với việc chèn / xóa trên mỗi bài kiểm tra. Quay trở lại nUnit , các thuộc tính FixtureSetupFixtureTeardowngiúp thiết lập dữ liệu cho nhiều thử nghiệm cùng một lúc.

Tôi sẽ sử dụng khung thử nghiệm qua thử / bắt vì nhiều tính năng thử nghiệm này được tích hợp vào khung. xUnit, nUnit, thậm chí cả khung thử nghiệm tích hợp của Microsoft đều là những lựa chọn chắc chắn và sẽ giúp thiết lập và dọn sạch các bản ghi cơ sở dữ liệu theo một cách nhất quán.


8

Điểm mà bạn nên nhắm đến với các thử nghiệm như vậy là càng nhiều trong số chúng càng có thể tương tác với một cơ sở dữ liệu, chứ không phải là chính cơ sở dữ liệu. Cách tiêu chuẩn để đạt được điều này là đưa lớp truy cập DB vào logic bạn đang kiểm tra ở đây, sử dụng các giao diện. Bằng cách đó, mã kiểm tra có thể tạo các bộ dữ liệu trong bộ nhớ trước mỗi thử nghiệm và sau đó loại bỏ chúng sau đó. Các bài kiểm tra sau đó có thể chạy song song và sẽ không ảnh hưởng lẫn nhau. Điều này làm cho bài kiểm tra của bạn nhanh hơn, dễ viết và dễ hiểu hơn và mạnh mẽ hơn.

Sau đó, bạn cần kiểm tra chính lớp truy cập DB thực tế. Bởi vì bạn sẽ chỉ có một vài trong số các thử nghiệm này, ví dụ, chúng có thể tạo một bảng thử nghiệm (hoặc thậm chí cả cơ sở dữ liệu), duy nhất cho thử nghiệm đó và điền vào đó với dữ liệu thử nghiệm. Sau khi thử nghiệm đã chạy, toàn bộ bảng thử nghiệm / DB sẽ bị hủy. Một lần nữa, các thử nghiệm này sẽ có thể chạy song song, do đó sẽ không có tác động đáng kể đến thời gian thực hiện thử nghiệm tổng thể.


Vâng, đó là một chút thay đổi đối với chúng tôi ngay bây giờ (chúng tôi đã bắt đầu thử nghiệm đơn vị 3 tháng trước). Giả sử, hiện tại, chúng ta sẽ sử dụng một cơ sở dữ liệu thực tế để kiểm tra, thứ tự an toàn / tiêu chuẩn để thực hiện việc này là gì - xóa mọi thứ, chèn mọi thứ và sau đó chạy thử nghiệm?
dialex

1
Nếu cơ cấu lại nằm ngoài câu hỏi, thì - trong trường hợp của bạn - câu trả lời của @ JonRaynor cung cấp tùy chọn tốt nhất của bạn.
David Arno

5

Vấn đề lớn với cơ sở dữ liệu và kiểm tra (đơn vị-) là cơ sở dữ liệu rất tốt trong việc duy trì công cụ.

Giải pháp thông thường là không sử dụng cơ sở dữ liệu thực tế trong các bài kiểm tra đơn vị của bạn, mà thay vào đó, giả lập cơ sở dữ liệu hoặc sử dụng cơ sở dữ liệu trong bộ nhớ có thể dễ dàng bị xóa hoàn toàn giữa các bài kiểm tra.
Chỉ khi kiểm tra mã tương tác trực tiếp với cơ sở dữ liệu hoặc trong các thử nghiệm từ đầu đến cuối thì cơ sở dữ liệu thực tế mới được sử dụng.


5

Làm việc trên Máy chủ C # với SQL Server và PetaPoco , đây là cách tiếp cận chúng tôi đã thực hiện để dọn sạch dữ liệu trong Bài kiểm tra đơn vị.

Một bài kiểm tra đơn vị điển hình sẽ có Cài đặt và Teardown như sau:

[TestFixture]
internal class PlatformDataObjectTests
{
    private IDatabaseConfiguration _dbConfig;
    private Database _pocoDatabase;
    private PlatformDataObject _platformDto;

    [SetUp]
    public void Setup()
    {
        _dbConfig = new CommonTestsAppConfig().GetDatabaseConfiguration();
        _pocoDatabase = new Database(_dbConfig.ConnectionString, SqlClientFactory.Instance);
        _platformDto = new PlatformDataObject(_pocoDatabase);
        _platformDto.BeginTransaction();
    }

    [TearDown]
    public void TearDown()
    {
        Console.WriteLine("Last Sql: {0}", _pocoDatabase.LastCommand);

        _platformDto.RollbackTransaction();
        _platformDto.Dispose();
    }

    // ... 
}

Trong đó PlatformDataObject là một lớp chịu trách nhiệm giao tiếp với cơ sở dữ liệu, ví dụ như thực hiện Chọn Chèn Cập nhật Xóa. Tất cả các loại * DataObject kế thừa ServerDataObject - lớp cơ sở có các phương thức để hủy bỏ, khôi phục hoặc thực hiện giao dịch.

/// <summary>
/// A Data-Transfer Object which allows creation and querying of Platform types from the database
/// </summary>
[ExportType(typeof(IPlatformDataObject))]
public class PlatformDataObject : ServerDataObject, IPlatformDataObject
{
    private static readonly ILog Log = LogManager.GetLogger(typeof (ProductDataObject));

    private const string PlatformTable = "t_Platform";

    public PlatformDataObject(IPocoDatabase pocoDatabase) : base(pocoDatabase)
    {
    }

    ... 
}

/// <summary>
/// A base Data-Transfer Object type
/// </summary>
public abstract class ServerDataObject : IServerDataObject
{
    protected const string Star = "*";

    private readonly IPocoDatabase _pocoDatabase;

    public ServerDataObject(IPocoDatabase pocoDatabase)
    {
        _pocoDatabase = pocoDatabase;
    }

    public string LastCommand
    {
        get { return PocoDatabase.LastCommand; }
    }

    public IPocoDatabase PocoDatabase
    {
        get { return _pocoDatabase; }
    }

    public int TransactionDepth
    {
        get { return _pocoDatabase.TransactionDepth; }
    }

    public bool TransactionAborted { get; private set; }

    public void BeginTransaction()
    {
        _pocoDatabase.BeginTransaction();
    }

    public void AbortTransaction()
    {
        _pocoDatabase.AbortTransaction();
    }

    public void RollbackTransaction()
    {
        TransactionAborted = true;
    }

    public virtual void Dispose()
    {
        if (TransactionAborted)
            _pocoDatabase.AbortTransaction();
        else
            _pocoDatabase.CompleteTransaction();
    }
}

Tất cả các bài kiểm tra đơn vị sẽ gọi RollbackTransaction (), cuối cùng sẽ gọi IDbTransaction.Rollback ().

Trong các thử nghiệm, chúng tôi thấy rằng thường xuyên tạo một phiên bản mới của * DataObject, tạo một số hàng bằng cách sử dụng các câu lệnh Chèn, thực hiện các thử nghiệm trên chúng (Chọn, Cập nhật, v.v.) và sau đó quay lại.

Chúng tôi có thể thiết lập một tập hợp dữ liệu thử nghiệm trước khi tất cả các thử nghiệm được chạy bằng SetUpFixture - một lớp chạy một lần trước khi tất cả các thử nghiệm được chạy và xóa / khôi phục dữ liệu sau khi tất cả các thử nghiệm được chạy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.