2013-02-12 29 views
17

Tôi có một vài hạt trong ngữ cảnh mùa xuân có trạng thái, vì vậy tôi muốn đặt lại trạng thái đó trước/sau khi kiểm tra đơn vị.Làm thế nào tôi có thể nhận được một danh sách các hạt đậu ngay lập tức từ mùa xuân?

Ý tưởng của tôi là thêm một phương thức vào lớp trợ giúp chỉ qua tất cả các bean trong ngữ cảnh mùa xuân, kiểm tra các phương thức được chú thích với @Before hoặc @After và gọi chúng.

Làm cách nào để có danh sách instantiated đậu từ ApplicationContext?

Lưu ý: Các giải pháp đơn giản lặp qua tất cả các bean được xác định là vô ích bởi vì tôi có nhiều đậu lười và một số không được khởi tạo vì điều đó sẽ thất bại đối với một số thử nghiệm (ví dụ: tôi có một hạt cần java.sql.DataSource. làm việc bởi vì họ không cần đậu đó).

+1

có thể xác định "Sau khi" pointcut http://static.springsource.org/spring/docs/3.0.x/reference/aop.html –

+0

Chú thích @DirtiesContext trong bài kiểm tra đơn vị của bạn không làm những gì bạn muốn? –

+0

@NicolasMommaerts: Không. Đặt lại một vài hạt sẽ rẻ hơn nhiều so với việc tạo toàn bộ bối cảnh từ đầu một lần nữa. –

Trả lời

21

Ví dụ:

public static List<Object> getInstantiatedSigletons(ApplicationContext ctx) { 
      List<Object> singletons = new ArrayList<Object>(); 

      String[] all = ctx.getBeanDefinitionNames(); 

      ConfigurableListableBeanFactory clbf = ((AbstractApplicationContext) ctx).getBeanFactory(); 
      for (String name : all) { 
       Object s = clbf.getSingleton(name); 
       if (s != null) 
        singletons.add(s); 
      } 

      return singletons; 

    } 
+0

'getSingleton()' hoạt động hoàn hảo cho tôi. Cập nhật ý kiến ​​của tôi (xem câu trả lời của riêng tôi) –

+0

@AaronDigulla Tôi đang làm việc với 'Spring-WebMVC'. Làm thế nào tôi có thể truy cập vào 'WebApplicationContext' cho' DispatcherServlet' của tôi? Nếu không có nó, tôi không thể lặp lại các hạt cà phê. – smwikipedia

+1

@AaronDigulla Tôi đã giải quyết nó. Tôi có thể sử dụng giao diện 'ApplicationContextAware'. Tham khảo: http://stackoverflow.com/questions/9602664/print-all-the-spring-beans-that-are-loaded – smwikipedia

3

Tôi không chắc liệu điều này có giúp ích cho bạn hay không.

Bạn cần tạo chú thích của riêng mình, ví dụ: MyAnnot. Và đặt chú thích đó lên lớp bạn muốn. Và sau đó sử dụng mã sau đây bạn có thể nhận được đậu instantiated.

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); 
scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnot.class)); 
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("com.xxx.yyy")){ 
    System.out.println(beanDefinition.getBeanClassName()); 
} 

Bằng cách này bạn có thể nhận được tất cả các hạt cà phê có chú thích tùy chỉnh của bạn.

0

Tôi đã tạo một gist ApplicationContextAwareTestBase.

lớp

helper này thực hiện hai điều:

  1. Nó đặt tất cả các lĩnh vực nội thành vô giá trị. Điều này cho phép Java giải phóng bộ nhớ không còn được sử dụng nữa. Nó ít hữu ích hơn với Spring (mặc dù bối cảnh Spring vẫn giữ nguyên các tham chiếu đến tất cả các bean).

  2. Nó cố gắng tìm tất cả các phương pháp được chú thích bằng @After trong tất cả các hạt trong ngữ cảnh và gọi chúng sau khi thử nghiệm.

Bằng cách đó, bạn có thể dễ dàng đặt lại trạng thái đơn/mocks mà không phải phá hủy/làm mới ngữ cảnh.

Ví dụ: Bạn có một DAO giả:

public void MockDao implements IDao { 

    private Map<Long, Foo> database = Maps.newHashMap(); 

    @Override 
    public Foo byId(Long id) { return database.get(id)); 

    @Override 
    public void save(Foo foo) { database.put(foo.getId(), foo); } 

    @After 
    public void reset() { database.clear(); } 
} 

Các chú thích sẽ đảm bảo reset() sẽ được gọi sau mỗi bài kiểm tra đơn vị để dọn dẹp tình trạng nội bộ.

3

tôi phải cải thiện nó một chút

@Resource 
AbstractApplicationContext context; 

@After 
public void cleanup() { 
    resetAllMocks(); 
} 

private void resetAllMocks() { 
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); 
    for (String name : context.getBeanDefinitionNames()) { 
     Object bean = beanFactory.getSingleton(name); 
     if (Mockito.mockingDetails(bean).isMock()) { 
      Mockito.reset(bean); 
     } 
    } 
} 
0

Sử dụng các câu trả lời trước đó, tôi đã cập nhật này để sử dụng Java 8 Streams API:

@Inject 
private ApplicationContext applicationContext; 

@Before 
public void resetMocks() { 
    ConfigurableListableBeanFactory beanFactory = ((AbstractApplicationContext) applicationContext).getBeanFactory(); 
    Stream.of(applicationContext.getBeanDefinitionNames()) 
      .map(n -> beanFactory.getSingleton(n)) 
      // My ConfigurableListableBeanFactory isn't compiled for 1.8 so can't use method reference. If yours is, you can say 
      // .map(ConfigurableListableBeanFactory::getSingleton) 
      .filter(b -> Mockito.mockingDetails(b).isMock()) 
      .forEach(Mockito::reset); 
} 
Các vấn đề liên quan