Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce @Reset as alternative to @DirtiesContext in TestContext framework [SPR-17108] #21645

Closed
spring-projects-issues opened this issue Jul 31, 2018 · 5 comments
Assignees
Labels
in: test status: declined type: enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Jul 31, 2018

Dipanshu opened SPR-17108 and commented

Overview

I have been using the SpringRunner in lots of tests and used a common way which is using @ContextConfiguration to load beans and create the ApplicationContext. However sometimes I need to have some way to tell Spring that some beans need to be freshly recreated in the same ApplicationContext.

I understand there is one way to do this using @DirtiesContext which destroys the existing ApplicationContext and creates a new one. But when I use this, beans which are not even dirty are also destroyed with the ApplicationContext which creates a performance issue.

Why do we want to remove supporting beans which are not even used in that particular test?

Example: database connection beans - Why do we want to re-establish a DB connection because only a single bean is modified and we have used @DirtiesContext.

We need some way to reset the ApplicationContext that would replace dirty beans with fresh ones.

Proposal

A new @Reset annotation could be introduced to achieve that.


No further details from SPR-17108

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 1, 2018

Sam Brannen commented

We need someway to reset context which should replace dirty beans with fresh ones.

Spring cannot know what beans are dirty.

So, how do you propose Spring would achieve that?

Note that ConfigurableApplicationContext defines a refresh() method, but that resets/restarts the entire ApplicationContext.

So what information would you supply via the proposed @Reset annotation?

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 1, 2018

Dipanshu commented

okay I understand Spring does not know about which beans are dirty. But I think tests (and their authors) know which beans are dirty so can this annotation be helpful ?

@Reset({ EmbeddedDatabase.class, StatefulBean.class })

As an author of the test, I know what beans are dirty, so I can decide whether to choose @Reset({ Class<?>[] beans }) or @DirtiesContext.

This is just one way off the top of my head, because I have never gone into code level details of how Spring performs dependency injection.

One question:

  1. Is there any stage where Spring can replace dirty instantiated-beans with the freshly created ones? I saw @MockBean implementation and how it replaces real beans, but I think that is done before beans are initialized.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 1, 2018

Sam Brannen commented

so can this annotation be helpful ?

@Reset({ EmbeddedDatabase.class, StatefulBean.class })

That would be one possible way to achieve your goal. That's "by type", but a robust implementation might need to support "by name" or "by qualifier" in addition to "by type".

Note, however, that there are some challenges to overcome.

  1. a single bean may be part of an object graph, meaning it may depend on other other beans or it may be depended on by other beans.
  2. the given bean may be in use by another test at the same time -- for example, if tests are executing in parallel.

To solve the first challenge, Spring would have to effectively update all beans that depend on the refreshed bean.

To solve the second challenge, Spring would have to ensure that there are no race conditions regarding to the bean being refreshed.

As far as I know, the only reliable solution to these challenges is currently only possible via the Spring Cloud Refresh Scope.

Since that functionality already exists, I'd recommend you look into that.

Is there any stage where Spring can replace dirty instantiated-beans with the freshly created ones?

No, I don't think so.

I saw @MockBean implementation and how it replaces real beans, but I think that is done before beans are initialized.

That's correct. Spring Boot's testing support for @MockBean actually replaces the bean in the ApplicationContext before the ApplicationContext is fully initialized and ready to use. In any case, that is a special feature of Spring Boot Test and therefore not functionality from Core Spring.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 1, 2018

Sam Brannen commented

Note that Spring Cloud's RefreshScope resides in the spring-cloud-context module.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Dec 5, 2018

Rossen Stoyanchev commented

Resolving due to inactivity.

@spring-projects-issues spring-projects-issues added status: declined in: test type: enhancement labels Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test status: declined type: enhancement
Projects
None yet
Development

No branches or pull requests

2 participants