Có phải thực tế xấu cho các bài kiểm tra đơn vị là phụ thuộc lẫn nhau?


9

Hãy nói rằng tôi có một số loại bài kiểm tra đơn vị như thế này:

let myApi = new Api();

describe('api', () => {

  describe('set()', () => {
    it('should return true when setting a value', () => {
      assert.equal(myApi.set('foo', 'bar'), true);
    });
  });

  describe('get()', () => {
    it('should return the value when getting the value', () => {
      assert.equal(myApi.get('foo'), 'bar');
    });
  });

});

Vì vậy, bây giờ tôi có 2 bài kiểm tra đơn vị. Người ta đặt một giá trị trong API. Một thử nghiệm khác để đảm bảo giá trị phù hợp được trả về. Tuy nhiên, bài kiểm tra thứ 2 phụ thuộc vào bài kiểm tra đầu tiên. Tôi có nên thêm vào một .set()phương thức trong thử nghiệm thứ 2 trước get()mục đích duy nhất là đảm bảo thử nghiệm thứ 2 không phụ thuộc vào bất cứ điều gì khác không?

Ngoài ra, trong ví dụ này tôi có nên khởi tạo myApicho mỗi bài kiểm tra thay vì thực hiện một lần trước khi kiểm tra không?

Câu trả lời:


15

Vâng, đó là thực tế xấu. Các bài kiểm tra đơn vị cần chạy độc lập với nhau, vì cùng một lý do mà bạn cần bất kỳ chức năng nào khác để chạy độc lập: bạn có thể coi nó là một đơn vị độc lập.

Tôi có nên thêm vào một phương thức .set () trong thử nghiệm thứ 2 trước get () với mục đích duy nhất là đảm bảo thử nghiệm thứ 2 không phụ thuộc vào bất cứ điều gì khác không?

Đúng. Tuy nhiên, nếu đây chỉ là các phương thức getter và setter trần, chúng không chứa bất kỳ hành vi nào và bạn thực sự không cần phải kiểm tra chúng, trừ khi bạn có tiếng về những thứ béo ngậy theo cách mà getter / setter biên dịch nhưng đặt hoặc lấy trường sai.


Trong ví dụ của tôi, giả sử myApilà một đối tượng được khởi tạo. Tôi có nên xác nhận lại myApitrong mỗi bài kiểm tra đơn vị? Hoặc là sử dụng lại giữa các thử nghiệm có khả năng gây ra thử nghiệm để cho kết quả dương tính giả, v.v. Và vâng, ví dụ của tôi là một thứ getter / setter đơn giản hóa nhưng thực tế nó sẽ phức tạp hơn nhiều.
Jake Wilson

1
@JakeWilson Có một cuốn sách tên là Thử nghiệm đơn vị thực dụng đi qua những điều cơ bản của thử nghiệm đơn vị, chẳng hạn như làm thế nào để tránh các thử nghiệm can thiệp lẫn nhau, v.v.
rwong

Một ví dụ khác: nếu bạn sử dụng JUnit, thứ tự của hàm của bạn không được xác định theo thứ tự bạn đã viết chúng trong theclass. @JakeWilson Nếu api của bạn không trạng thái, bạn có thể sử dụng lại nó, nếu không chứng minh lại.
Walfrat

2

Cố gắng tuân theo cấu trúc sắp xếp hành động-khẳng định cho mỗi bài kiểm tra.

  1. Sắp xếp các đối tượng của bạn, vv và đặt chúng vào một trạng thái đã biết (một vật cố kiểm tra). Đôi khi, giai đoạn này bao gồm các xác nhận để cho thấy rằng bạn thực tế đang ở trong trạng thái mà bạn nghĩ là bạn.
  2. Act, nghĩa là: thực hiện hành vi bạn đang kiểm tra.
  3. Khẳng định rằng bạn đã có kết quả như mong đợi.

Bạn kiểm tra không bận tâm để tạo ra một trạng thái đã biết trước, vì vậy chúng vô nghĩa trong sự cô lập.

Ngoài ra, kiểm tra đơn vị không nhất thiết chỉ kiểm tra một phương pháp duy nhất - kiểm tra đơn vị nên kiểm tra một đơn vị. Thông thường, đơn vị này là một lớp. Một số phương pháp như get()chỉ có ý nghĩa kết hợp với một phương pháp khác.

Kiểm tra getters và setters là hợp lý, đặc biệt là trong các ngôn ngữ động (chỉ để đảm bảo rằng chúng thực sự ở đó). Để kiểm tra một getter, trước tiên chúng ta cần cung cấp một giá trị đã biết. Điều này có thể xảy ra thông qua các hàm tạo hoặc thông qua một setter. Hoặc được xem khác nhau: kiểm tra getter ẩn trong các kiểm tra của setter và của constructor. Và setter, nó luôn luôn trả về true, hay chỉ khi giá trị được thay đổi? Điều này có thể dẫn đến các thử nghiệm sau (mã giả):

describe Api:

  it has a default value:
    // arrange
    api = new Api()
    // act & assert
    assert api.get() === expected default value

  it can take custom values:
    // arrange & act
    api = new Api(42)
    // act & assert
    assert api.get() === 42

  describe set:

    it can set new values:
      // arrange
      api = new Api(7)
      // act
      ok = api.set(13)
      // assert
      assert ok === true:
      assert api.get() === 13

    it returns false when value is unchanged:
      // arrange
      api = new Api(57)
      // act
      ok = api.set(57)
      // assert
      assert ok === false
      assert api.get() === 57

Sử dụng lại trạng thái từ một bài kiểm tra trước sẽ làm cho các bài kiểm tra của chúng tôi khá mong manh. Sắp xếp lại các bài kiểm tra hoặc thay đổi giá trị chính xác trong một bài kiểm tra có thể khiến các bài kiểm tra dường như không liên quan đến thất bại. Giả sử một trạng thái cụ thể cũng có thể ẩn các lỗi nếu nó khiến các bài kiểm tra vượt qua mà thực sự thất bại. Để ngăn chặn điều này, một số người chạy thử nghiệm có các tùy chọn để chạy các trường hợp thử nghiệm theo thứ tự ngẫu nhiên.

Tuy nhiên, có những trường hợp khi chúng tôi sử dụng lại trạng thái được cung cấp bởi thử nghiệm trước đó. Đặc biệt, khi tạo một vật cố thử nghiệm mất rất nhiều thời gian để chúng tôi kết hợp nhiều trường hợp thử nghiệm vào một bộ thử nghiệm. Mặc dù các thử nghiệm này mong manh hơn, nhưng hiện tại chúng vẫn có thể có giá trị hơn vì chúng có thể được thực hiện nhanh hơn và thường xuyên hơn. Trong thực tế, việc kết hợp các bài kiểm tra là mong muốn bất cứ khi nào các bài kiểm tra liên quan đến một thành phần thủ công, khi cần một cơ sở dữ liệu lớn hoặc khi kiểm tra các máy trạng thái.

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.