Java - Làm cách nào để trao đổi đường dẫn tệp tài nguyên cho tệp thử nghiệm trong quá trình thử nghiệm đơn vị?


8

Tôi có một tệp tài nguyên có một số cài đặt. Tôi có một lớp ResourceLoader tải các cài đặt từ tệp này. Lớp này hiện đang là một lớp singleton háo hức. Ngay khi lớp này tải, nó sẽ đọc các cài đặt từ tệp (đường dẫn tệp được lưu dưới dạng trường không đổi trong lớp khác). Một số trong các cài đặt này không phù hợp cho các bài kiểm tra đơn vị. Ví dụ: tôi có thời gian ngủ của luồng trong tệp này, có thể là hàng giờ cho mã sản xuất nhưng tôi muốn nó là một vài mili giây cho các thử nghiệm đơn vị. Vì vậy, tôi có một tệp tài nguyên thử nghiệm khác có một bộ giá trị khác. Câu hỏi của tôi là làm cách nào để hoán đổi tệp tài nguyên chính với tệp kiểm tra này trong quá trình kiểm tra đơn vị? Dự án là một dự án maven và tôi đang sử dụng testng làm khung thử nghiệm. Đây là một số cách tiếp cận tôi

  1. Sử dụng @B BeforeSuite và sửa đổi biến hằng FilePath để trỏ đến tệp thử nghiệm và sử dụng @AfterSuite để trỏ nó trở lại tệp gốc. Điều này có vẻ như đang hoạt động nhưng tôi nghĩ bởi vì lớp ResourceLoader ngay lập tức được kích hoạt, không có gì đảm bảo rằng phương thức @B BeforeSuite sẽ luôn thực thi trước khi lớp ResourceLoader được tải và do đó các thuộc tính cũ có thể được tải trước khi đường dẫn tệp được thay đổi. Mặc dù hầu hết các trình biên dịch chỉ tải một lớp khi nó được yêu cầu, tôi không chắc đây có phải là một yêu cầu đặc tả java không. Vì vậy, trong lý thuyết, điều này có thể không hoạt động cho tất cả các trình biên dịch java.

  2. Truyền đường dẫn tệp tài nguyên dưới dạng đối số dòng lệnh. Tôi có thể thêm đường dẫn tệp tài nguyên thử nghiệm làm đối số dòng lệnh trong cấu hình Surefire trong pom. Điều này có vẻ hơi quá.

  3. Sử dụng cách tiếp cận trong 1. và làm cho ResourceLoader trở nên lười biếng ngay lập tức. Điều này đảm bảo rằng nếu @B BeforeMethod được gọi trước cuộc gọi đầu tiên tới ResourceLoader.getInstance (). GetProperty (..), ResourceLoader sẽ tải đúng tệp. Điều này có vẻ tốt hơn so với 2 cách tiếp cận đầu tiên nhưng tôi nghĩ rằng việc tạo ra một lớp đơn lẻ lười biếng ngay lập tức làm cho nó trở nên xấu xí vì tôi không thể sử dụng một mô hình đơn giản như biến nó thành một enum và như vậy (ví dụ như trường hợp tức thời háo hức).

Đây có vẻ như là một kịch bản phổ biến, cách phổ biến nhất về nó là gì?


Là làm lại ứng dụng của bạn để sử dụng một thư viện cấu hình tốt hơn là một tùy chọn?
Thorbjørn Ravn Andersen

Vâng, tôi chỉ muốn biết cách tiêu chuẩn để làm điều này. Tôi đang mở để làm lại ứng dụng.
Marko Cain

Cách tiêu chuẩn duy nhất là sử dụng các thuộc tính môi trường và / hoặc hệ thống. Điều đó thường là quá hạn chế vì chúng khó cung cấp và ghi đè từ dòng lệnh trong các bài kiểm tra. Tôi sẽ đề nghị bạn thêm thông tin vào câu hỏi của bạn về những gì bạn cần và cách bạn mong đợi để có thể định cấu hình ứng dụng của mình với một vài trường hợp sử dụng. Bạn có thể muốn nghĩ đến việc chuyển các giá trị cấu hình trong hàm tạo của các lớp cần chúng.
Thorbjørn Ravn Andersen

Câu trả lời:


7

Tất cả các singletons hoặc háo hức hoặc lười biếng ngay lập tức là chống mẫu . Việc sử dụng singletons làm cho việc kiểm tra đơn vị khó hơn vì không có cách nào dễ dàng để chế nhạo singleton.

Phương pháp tĩnh giả

Một cách giải quyết là sử dụng PowerMock để giả định phương thức tĩnh trả về thể hiện singleton.

Sử dụng tiêm phụ thuộc

Một giải pháp tốt hơn là sử dụng tiêm phụ thuộc. Nếu bạn đã sử dụng khung tiêm phụ thuộc (ví dụ Spring, CDI), hãy cấu trúc lại mã để tạo ResourceLoadermột bean được quản lý với phạm vi singleton .

Nếu bạn không sử dụng khung tiêm phụ thuộc, tái cấu trúc dễ dàng sẽ thực hiện thay đổi cho tất cả các lớp bằng cách sử dụng singleton ResourceLoader:

public class MyService {

  public MyService() {
    this(ResourceLoader.getInstance());
  }

  public MyService(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
  }
}

Và sau đó trong bài kiểm tra đơn vị giả ResourceLoaderbằng Mockito

ResourceLoader resourceLoader = mock(ResourceLoader.class);
when(ResourceLoader.getProperty("my-property")).thenReturn("10");
MyService myService = new MyService(resourceLoader);

Cấu hình bên ngoài

Một cách tiếp cận khác là đặt một tệp có cài đặt kiểm tra bên dưới src/test/resources. Nếu bạn lưu trữ cài đặt trong src/main/resources/application.properties, một tệp src/test/resources/application.propertiessẽ ghi đè lên nó.

Ngoài ra, cấu hình bên ngoài vào một tệp không được đóng gói trong JAR là một ý tưởng tốt. Bằng cách này, tệp src/main/resources/application.propertiessẽ chứa các thuộc tính mặc định và một tệp được truyền bằng tham số dòng lệnh sẽ ghi đè các thuộc tính này. Vì vậy, một tệp có thuộc tính kiểm tra cũng sẽ được truyền dưới dạng tham số dòng lệnh. Xem cách Spring xử lý cấu hình bên ngoài .

Sử dụng thuộc tính hệ thống Java

Cách tiếp cận thậm chí dễ dàng hơn là cho phép ghi đè các thuộc tính mặc định bằng Thuộc tính hệ thống trong phương thức ResourceLoader.getInstance().getProperty()và vượt qua các thuộc tính thử nghiệm theo cách này

public String getProperty(String name) {
  // defaultProperties are loaded from a file on a file system:
  // defaultProperties.load(new FileInputStream(new File(filePath)));
  // or from a file in the classpath:
  // defaultProperties.load(ResourceLoader.class.getResourceAsStream(filePath));
  return System.getProperty(name, defaultProperties.get(name));
}

0

Kiểm tra nếu bạn trong jUnit

Bạn cũng có thể kiểm tra trong thời gian chạy xem jUnit có đang chạy hay không và sau đó trao đổi đường dẫn. Điều đó sẽ làm việc như thế này ( chưa được kiểm tra ):

public static funktionToTest() {
    StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
    List<StackTraceElement> list = Arrays.asList(stackTraceElements);
    String path = "/origin/path/to/your/file"; // here can you set the default path to your rescource
    for (StackTraceElement stackTraceElement : list) {
        if (stackTraceElement.getClassName().startsWith("org.junit.")) {
            path = "/path/only/in/jUnit/test"; // and here the normal path
        }           
    }
    //do what you want with the path
}
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.