0

I have a project with spring MVC v5.0.8, Java 8
I've made some integration test from controller to database, and now, I want to add one which will test what happens if the first part of a transactional behavior failed. I'll ensure that the transaction is effectively roll-backed.
So, I've to override a DAO to make it fail. After some research, came up a simple idea : override spring config for that test : Overriding an Autowired Bean in Unit Tests
My test work fine now, but the problem is that this configuration is shared with other test from other classes, even if it is in one class. How can I make it specific to that test ?

(If b creation fail, a must be roll-backed) Failing test :

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@EnableWebMvc
@Sql({"/sqlfiles/clean-data.sql"})
public class AControllerFailDaoIt {

    @Configuration
    static class ConfigFailDao extends ApplicationConfiguration{
        @Bean
        @Primary
        public BDao getBDao() {
            return new BDao() {
                //Overriding method to make it fail
            };
        }
    }

    @Autowired
    AController aController;

    @Autowired
    ADao aDao;

    @Test
    public void should_not_create_a_if_b_failed(){
        //creation of a

        //assert nor a nor b are created
    }
}

Nominal test case :

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@EnableWebMvc
@ContextConfiguration(classes = {ApplicationConfiguration.class, CustomWebAppConfiguration.class})
@Sql({"/sqlfiles/clean-data.sql"}) //"/sqlfiles/account-test.sql"
public class AControllerIT {

    @Autowired
    AController aController;

    @Autowired
    ADao aDao;

    @Autowired
    BDao bDao;

    @Test
    public void should_create_a_and_corresponding_b(){
        //create a
        //assert that both a and b are created
    }
}

ApplicationConfiguration (which is test-specific)

@Configuration
@ComponentScan(basePackages = "my.base.package")
class ApplicationConfiguration implements WebMvcConfigurer {
}

Note : my Integration test classes are within the base package, does it matters ?
I found an option : put the fail test config in an external class, and call it only on my fail test, but it still doesn't work.
At the moment, I ran out of ideas, so I'll welcome your help !

MLem
  • 59
  • 1
  • 10
  • If you are specifying the configuration only in this test class @ContextConfiguration annotation then I don't think it will be share with other test classes? – DEVAS Aug 25 '18 at 17:52
  • I will suggest rather than overriding dao execute test with specific data that throws some exception or use mocking to throw some exception on second step. – DEVAS Aug 25 '18 at 18:02
  • Thanks for your time ! If I make two separate configuration, let's say ApplicationConfiguration for regular test, and ApplicationConfigurationFail for this one, they all get the fail config (probably because of the @Primary as Guts stated), even If I call @ContextConfiguration(classes = {ApplicationConfiguration.class, CustomWebAppConfiguration.class}) for the regular test. – MLem Aug 25 '18 at 22:15
  • I'm trying to figure a way to make specific data to throws some exception, but the only way if to get an already existing ID, but since they are generated via UUID.randomUUID() in the Dao, I don't know what I can do. – MLem Aug 25 '18 at 22:20

2 Answers2

0

I suggest you to use @Qualifier annotation.

  1. Instead of putting @Primary above getBDao() method in your configuration put @Qualifier with some name i.e.:

    @Bean
    @Qualifier("BDaoTest")
    public BDao getBDao() {
        return new BDao() {
            //Overriding method to make it fail
        };
    }
    
  2. After that put @Primary on your default BDao implementation (in your default config).

  3. Then when you autowire this bean in your test you need to put this qualifier:

    @Autowired
    @Qualifier("BDaoTest")
    BDao bDao;
    
Guts
  • 748
  • 4
  • 10
  • The problem is that the controller autowire a service class, that autowire the BDao, and that's this autowired instance that I need to replace on my test. Actually, hey are autowired in my test class to query the database, but technically I don't need the BDao in the fail test, so I'm removing it. – MLem Aug 25 '18 at 22:09
0

I got it working. In a bad way, so if you have a better option, I'm in. But I didn't found a way to make my test fail by data... Which would be the better one.
So, I've found that the @Configuration annotation make a class scanned. Spring doc.
I just made my fail configuration in an outer class, and remove the @Configuration annotation. So it won't be scanned by other test configuration. Then in my fail test class, I referenced it in the @ContextConfiguration annotation, so it is used. This way it work fine. I now have a problem with @Transactional, but that's not this thread.
Thanks to responders, you made me look in the right direction :-)

MLem
  • 59
  • 1
  • 10