2012-08-17 32 views
16

Đó là bình thường để thấy chức năng đăng nhập vào mãChúng ta có nên đơn vị kiểm tra đăng nhập?

public class A { 

private static final Log LOG = LogFactory.getLog(A.class); 

và sử dụng

 } catch (Exception e) { 
      LOG.error(e.getMessage(), e); 
      throw e; 
     } 

nhưng tôi chưa bao giờ thấy thậm chí kiểm tra đơn vị duy nhất cho mã như vậy.

Tắt khóa học Tôi thực hiện kiểm tra loại trừ ngoại lệ và loại ngoại lệ, nhưng tôi có nên viết kiểm tra để kiểm tra thông tin đăng nhập không? Tôi có xu hướng nghĩ rằng đăng nhập là một phần khác của hành vi hệ thống, do đó, nó thoát khỏi một cách hợp lý để trang trải nó trong các thử nghiệm.

Giả sử rằng tôi nên đề cập đến nó, có nghĩa là tôi nên thay đổi mã ban đầu của mình để chèn nhật ký giả và kiểm tra phương thức "lỗi" đã được gọi với thông báo dự kiến. Nhưng phải làm gì nếu lớp ban đầu của tôi là dịch vụ và nó được khởi tạo bởi mùa xuân, tôi có nên tiêm một số logger cũng như các phụ thuộc khác không?

Trả lời

9

Bạn không thể kiểm tra thư viện ghi nhật ký. Nhưng nó có thể là đáng giá để kiểm tra rằng khi một ngoại lệ được ném ra, lớp của bạn sẽ ghi lại một thông báo ở mức thích hợp. Những gì bạn đang thử nghiệm là mã của bạn làm điều đúng với thư viện đăng nhập.

Để làm cho mã ở trên có thể kiểm tra, hãy sử dụng tính năng tiêm phụ thuộc. Điều này giả định rằng trình ghi nhật ký thực hiện một giao diện, ILog. Bạn sẽ vượt qua trong logger như là một tham số constructor cho lớp A. Sau đó, mã kiểm thử sẽ tạo ra việc thực thi mô hình ILog và truyền nó vào hàm tạo. Không được hiển thị trong đoạn mã trên là cách ngoại lệ xuất hiện, nhưng có lẽ nó sẽ thông qua một số đối tượng phụ thuộc khác. Vì vậy, bạn giả lập đó là tốt, và làm cho nó ném một ngoại lệ. Sau đó kiểm tra xem mô hình ILog đã gọi phương thức error chưa. Có thể bạn muốn kiểm tra thông báo rằng nhật ký, nhưng điều đó có thể đi quá xa, bằng cách làm cho mã thử nghiệm trở nên mong manh.

+0

là nó cùng một cách tiếp cận mà tôi đã đề cập trong câu hỏi của tôi. Nhưng đối với tôi nó vẫn chưa rõ phải làm gì trong trường hợp dịch vụ mùa xuân vì thường LOG tạo ra cho mỗi lớp, vì vậy nó là lớp cụ thể và tôi không thể làm cho nó như là một singleton. –

+0

Nếu bạn không có bất kỳ sự kiểm soát mã nào để khởi tạo đối tượng Nhật ký, thật khó để kiểm tra hành vi, bởi vì bạn không thể sử dụng Nhật ký mô phỏng. Bạn có thể cho phép nó đăng nhập với đối tượng Log thực, sau đó kiểm tra xem một thư đã được đăng nhập chưa. Tuy nhiên, thật khó để tự động hóa! –

+0

Không, tôi đồng ý với bạn rằng mã đăng nhập phải được kiểm tra. Nó có nghĩa là chúng ta nên có setter cho LOG, vì vậy nó sẽ có thể vượt qua thử nghiệm đăng nhập thử nghiệm, nhưng phải làm gì trong trường hợp dịch vụ mùa xuân. Tôi đang suy nghĩ về 2 cách có thể: 1) có setter nhưng gọi chỉ từ test (có thể khó hạn chế tầm nhìn như vậy kể từ mùa xuân có thể tự động tiêm), 2) tiêm logger qua mùa xuân, nhưng trong trường hợp này thật khó để khởi tạo trình ghi nhật ký thích hợp. –

2

Tôi sẽ không kiểm tra mã đơn vị không làm gì ngoài việc gọi vào thư viện mà bạn tin tưởng.
Bạn có tin tưởng vào thư viện đăng nhập của mình không? Nếu thử nghiệm không thành công, có phải vì có lỗi trong thư viện hay đơn giản vì bạn chưa định cấu hình thư viện chính xác? Bạn có chăm sóc về việc thử nghiệm cấu hình không?

+14

Tôi không thử nghiệm cách hoạt động của thư viện ghi nhật ký, ý định của tôi là kiểm tra xem mã của tôi có ghi nhật ký không. –

1

Có, chúng tôi nên kiểm tra đăng nhập khi quá trình ghi nhật ký đang thực hiện điều gì đó được yêu cầu. Ví dụ, bạn có móc trong một số ứng dụng bên ngoài quét nhật ký cho một số sự kiện nhất định. Trong trường hợp đó bạn chắc chắn muốn đảm bảo việc ghi nhật ký được thực hiện.

Tất nhiên bạn không muốn kiểm tra mọi sự kiện đăng nhập, và tôi nghĩ rằng hầu hết chỉ ERROR (và không phải tất cả chúng) nên được kiểm tra.

Với khung công tác ghi nhật ký hiện đại như SLF4j, bạn có thể chỉ cần đưa trình xử lý tùy chỉnh lưu trữ các sự kiện trong bộ nhớ và có thể được xác nhận sau đó.

Có hai trong số họ mà tôi suy nghĩ của tôi ngay bây giờ:

SLF4JTesting: Yêu cầu không sửa đổi các cấu hình đăng nhập nhưng đòi hỏi phải tiêm một nhà máy khai thác gỗ mà có thể dẫn đến mã sửa đổi.

SLF4J Test: Không mạnh bằng slf4jtesting và dường như không được phát triển nhưng hoạt động tốt với mã hiện có. Không có sửa đổi ngoài cấu hình trình ghi nhật ký để kiểm tra.

Khi sử dụng Kiểm tra SLF4J, các xác nhận khá nghiêm ngặt và kiểm tra toàn bộ sự kiện để bình đẳng. Đối sánh tùy chỉnh có thể thú vị trong trường hợp như vậy:

public static Matcher<LoggingEvent> errorMessageContains(final String s) { 
    return new TypeSafeMatcher<LoggingEvent>() { 
     @Override 
     public void describeTo(final Description description) { 
      description.appendText(" type " + Level.ERROR + " should contain ") 
        .appendValue(s); 
     } 

     @Override 
     protected void describeMismatchSafely(final LoggingEvent item, final Description mismatchDescription) { 
      mismatchDescription.appendText(" was type ").appendValue(l) 
        .appendText(" message ").appendValue(item.getMessage()); 
     } 

     @Override 
     protected boolean matchesSafely(final LoggingEvent item) { 
      return item.getLevel().equals(Level.ERROR) 
        && item.getMessage().contains(s); 
     } 
    }; 
} 

Điều này chỉ kiểm tra xem tin nhắn có chứa văn bản không nếu nó bằng nhau. Vì vậy, khi thông báo được sửa đổi để sửa lỗi đánh máy hoặc cung cấp thêm chi tiết, kiểm tra sẽ không bị vỡ nếu phần thiết yếu vẫn còn chứa.

0

Nếu đăng nhập là yêu cầu kinh doanh và sẽ cung cấp giá trị doanh nghiệp (ví dụ: trong trường hợp thất bại, chẩn đoán hoặc giải quyết vấn đề), thì bạn nên coi nó là bất kỳ yêu cầu nào khác. Như vậy, bạn có lẽ nên viết các bài kiểm tra đơn vị không để xác minh rằng thư viện đăng nhập của bạn hoạt động, nhưng để xác minh rằng, trong các trường hợp dự kiến, mã của bạn sẽ ghi lại những gì cần.

Thông tin thêm về chủ đề này: https://ardalis.com/logging-and-monitoring-are-requirements

0

có một cách khác: bạn có thể thử LogFactory! ví dụ:

import junit.framework.Assert; 
import mockit.Mock; 
import mockit.MockUp; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.junit.Test; 

public class XXXTest { 
    class MyLog implements Log { 
     public static final String INFO = "info"; 

     private String logLevel; 
     private Object logContent; 

     public String getLogLevel() { 
      return logLevel; 
     } 

     public Object getLogContent() { 
      return logContent; 
     } 

     @Override 
     public void info(Object o) { 
      logLevel = "info"; 
      logContent = o; 
     } 

     //Implement other methods 
    } 

    @Test 
    public void testXXXFunction() { 
     final MyLog log = new MyLog(); 
     new MockUp<LogFactory>() { 
      @Mock 
      public Log getLog(String name) { 
       return log; 
      } 
     }; 

     //invoke function and log by MyLog 
     FunctionToBeTest.invoke(); 
     Assert.assertEquals("expected log text", log.getLogContent()); 
    } 
} 

chúc may mắn!

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