Beware of @DirtiesContext

  • @DirtiesContext is a Spring testing annotation.
  • It tells spring that the Class or test method with this annotation modifies the application context.
  • Once @DirtiesContext is used, the cached application context will be recreated.
  • @DirtiesContext is both a class and method level annotation.

The problems

Cost and speed of unit tests

Closing and recreating the application context is costly. Imagine a big project with a lot of classes and tests where we are using @DirtiesContext a lot. This will greatly slow the testing of the application.

False Negative tests

These are tests that should fail but are successfully running. Consider the below example which demonstrate a transaction error.

// Service interface
public interface ThemeParkRideService {
    /**
     * Find all rides
     *
     * @return list of ThemeParkRide
     */
    List<ThemeParkRide> getRides();

    /**
     * Create ride
     *
     * @param themeParkRide
     */
    void createRide(ThemeParkRide themeParkRide);
}

In the service implementation below, in the method createRide(themeParkRide), see the part throw new RuntimeException("Example error"). Here we are simulating a runtime error. The service also do not have an @Transactional annotation set.

// Service implementation
@RequiredArgsConstructor
@Service
public class ThemeParkRideServiceImpl implements ThemeParkRideService {
    
    private final ThemeParkRideRepository themeParkRideRepository;

    @Override
    public List<ThemeParkRide> getRides() {
        return themeParkRideRepository.findAll();
    }

    @Override
    public void createRide(ThemeParkRide themeParkRide) {
        themeParkRideRepository.save(themeParkRide);
        throw new RuntimeException("Example error");
    }
}
// Test class
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ThemeParkRideServiceBadTest {

    @Autowired
    private ThemeParkRideService service;
    @Autowired
    private ThemeParkRideRepository repository;

    @Test
    @Order(1)
    @DirtiesContext
    void testCreateRide() {
        ThemeParkRide ride = new ThemeParkRide("Rollercoaster",
                "Train ride",
                5,
                3);
        Assertions.assertThrows(RuntimeException.class, () ->
                service.createRide(ride));
    }

    @Test
    @Order(2)
    void testGetRides() {
        repository.save(
                new ThemeParkRide("Teacups",
                        "Spinning ride",
                        2,
                        4));
        List<ThemeParkRide> rideList = service.getRides();
        assertThat("One ride must be available", rideList, hasSize(1));
        assertThat("Name is Teacups", rideList.get(0).getName(), is("Teacups"));
    }
}

Here all the tests will run successfully as the testCreateRide() will get the expected RuntimeException and the testGetRides() will get one ThemeParkRide with name “Teacups”.

These are clearly a false negative tests as the @DirtiesContext annotation is hiding the transaction problem in the service implementation class.

The solution

Remove @DirtiesContext from the test method testCreateRide().

// Refactored test class
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ThemeParkRideServiceBadTest {

    @Autowired
    private ThemeParkRideService service;
    @Autowired
    private ThemeParkRideRepository repository;

    /**
     * Test method with a @DirtiesContext annotation to clean all created data after the test.
     * Test is expecting a RuntimeException
     */
    @Test
    @Order(1)
    void testCreateRide() {
        ThemeParkRide ride = new ThemeParkRide("Rollercoaster",
                "Train ride",
                5,
                3);
        Assertions.assertThrows(RuntimeException.class, () ->
                service.createRide(ride));
    }

    /**
     * Test method is checking data fetch
     */
    @Test
    @Order(2)
    void testGetRides() {
        repository.save(
                new ThemeParkRide("Teacups",
                        "Spinning ride",
                        2,
                        4));
        List<ThemeParkRide> rideList = service.getRides();
        assertThat("One ride must be available", rideList, hasSize(1));
        assertThat("Name is Teacups", rideList.get(0).getName(), is("Teacups"));
    }
}

Here only the test testCreateRide() will run successfully get the expected RuntimeException however the test testGetRides() will now fail as it is expecting one ThemeParkRide with name “Teacups” but instead is getting two rides. One with name “Teacups” and the other with name “Teacups”

The explanation

  • Spring rollbacks transactions on RuntimeException detection.
  • Since we did not use an @Transactional annotation in our service class, createRide() method will commit even though it encounters a RuntimeException.
  • The test method testGetRides() is now failing as the it is getting the committed data from createRide() also.
  • This is a correct behavior which alerts the developer that an @Transactional should be set in the service class.
  • @DirtiesContext was silently hiding the transactional problem.

46 Comments

Add Yours →

It’s a shame you don’t have a donate button! I’d certainly donate
to this brilliant blog! I suppose for now i’ll settle for bookmarking and adding your RSS feed to my Google account.
I look forward to fresh updates and will talk about this site with my Facebook group.
Talk soon!

I’m really impressed together with your writing abilities and
also with the structure for your weblog. Is that this a paid theme or did you customize it your self?

Anyway keep up the excellent quality writing, it is rare
to look a great weblog like this one these days..

Aw, this was an incredibly good post. Taking the time and actual effort to create a superb article… but what can I say… I put things off a lot and never manage to get anything done.

Nice post. I used to be checking constantly this blog and I
am inspired! Extremely helpful information specially the last section 🙂 I handle such information a lot.
I used to be seeking this particular information for a long time.

Thanks and best of luck.

An outstanding share! I’ve just forwarded this onto
a co-worker who has been doing a little homework on this.
And he actually ordered me breakfast because I discovered it for him…
lol. So allow me to reword this…. Thanks for the meal!!
But yeah, thanks for spending some time to talk about this matter here on your site.

I do not know whether it’s just me or if everybody
else encountering issues with your site. It seems like some of
the text on your posts are running off the screen. Can someone else please provide feedback and let me know if this is happening
to them as well? This might be a issue with my browser because I’ve had
this happen before. Kudos

Hi! This is kind of off topic but I need some help from an established blog.

Is it very hard to set up your own blog? I’m not very techincal but I
can figure things out pretty quick. I’m thinking about creating my own but I’m not
sure where to start. Do you have any ideas or suggestions?
With thanks

Great post. I used to be checking constantly this blog and I’m inspired!
Very useful information specifically the ultimate part 🙂 I take care of such
info a lot. I was looking for this particular information for a long time.
Thank you and good luck.

Excellent post. I was checking continuously
this blog and I am impressed! Extremely useful info specially
the last part 🙂 I care for such information a lot.
I was seeking this particular info for a very long time. Thank you and
best of luck.

Good day! This is my first comment here so I just wanted
to give a quick shout out and say I really enjoy reading through your blog
posts. Can you recommend any other blogs/websites/forums
that deal with the same subjects? Thank you!

Hey! I know this is somewhat off topic but I was wondering if you knew where I could get a captcha plugin for my comment
form? I’m using the same blog platform as yours and I’m having
trouble finding one? Thanks a lot!

After looking over a number of the blog posts on your site, I honestly appreciate your technique of
writing a blog. I saved as a favorite it to my bookmark site list and will be checking
back in the near future. Please visit my web site too and let me know what you think.

Greetings! I’ve been following your website for some time now and finally got the bravery to go ahead and give you a shout out from Humble
Tx! Just wanted to mention keep up the fantastic job!

Hi there, I found your blog by the use of Google while searching
for a related topic, your website came up, it appears to
be like good. I’ve bookmarked it in my google bookmarks.

Hello there, just was alert to your weblog thru Google,
and found that it is really informative. I am gonna be careful for brussels.
I will appreciate for those who continue this in future. A
lot of other people can be benefited from your writing.
Cheers!

This design is spectacular! You definitely know how to keep a reader
entertained. Between your wit and your videos, I was almost moved to start my own blog
(well, almost…HaHa!) Excellent job. I really loved what
you had to say, and more than that, how you presented it.

Too cool!

Superb site you have here but I was curious if
you knew of any forums that cover the same topics discussed in this article?

I’d really love to be a part of group where I can get feed-back from other
experienced people that share the same interest. If you have any suggestions, please let me know.

Cheers!

Howdy! This blog post couldn’t be written any better! Going through this post reminds me of my previous roommate!

He always kept preaching about this. I am going to forward this information to him.
Fairly certain he’s going to have a very good read. Thank you for
sharing!

Excellent post. I was checking constantly this weblog and I’m impressed!
Extremely useful info specially the remaining phase 🙂 I maintain such information a
lot. I was looking for this certain information for a long time.

Thank you and best of luck.

Hey There. I found your blog using msn. This is an extremely well written article.
I’ll make sure to bookmark it and come back to read more of your useful info.
Thanks for the post. I will definitely return.

I was suggested this website by my cousin. I’m not
sure whether this post is written by him as nobody else know such detailed about my difficulty.
You’re incredible! Thanks!

Great beat ! I wish to apprentice while you amend your website, how could i subscribe for
a blog web site? The account aided me a acceptable deal.
I had been a little bit acquainted of this your broadcast offered bright clear idea

Please let me know if you’re looking for a author
for your site. You have some really great articles and I think I would be
a good asset. If you ever want to take some of the load off, I’d love to write some content for your blog in exchange for
a link back to mine. Please shoot me an email if interested.
Regards!

Hi! I know this is kinda off topic but I was wondering which blog platform are you using for this website?
I’m getting tired of WordPress because I’ve had issues with
hackers and I’m looking at options for another platform.

I would be fantastic if you could point me in the direction of a good platform.

Make money trading opions.
The minimum deposit is 50$.
Learn how to trade correctly. How to earn from $50 to $15000 a day.

The more you earn, the more profit we get.
I really wish I am useful at all

Leave a Reply