Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correctly testing a Spring service [duplicate]

The following test fails with a NullPointerException on the line usersRepo.save(user);. I believe it's because when the test goes into the performProvision() function the usersRepo object is null.

However, when the web service is actually running and the endpoint for my controller is hit, everything works fine and the database is updated.

Any idea why the test fails? My idea was that PAutoProvision references the real database, whereas it should be dealing with the in-memory database so maybe there is some sort of conflict? I have also seen a lot of different examples with annotations set up differently, so I suppose that could be a problem too.

UsersRepo extends JpaRepository where PAutoProvision is a SQL table entity.

If this isn't enough information, I can provide the UsersRepo, PAutoProvision, and ProvisionController classes if necessary.

The Service:

@Service
public class ProvisionService {

    @Autowired
    private UsersRepo usersRepo;


    public String performProvision(UserData userData) {
        try {
            PAutoProvision user = new PAutoProvision(userData);
            usersRepo.save(user);  // OOTB CRUD repository functionality of springData to update/insert record data
            return String.format("Success: User %s has been added to the database", userData.getUserId());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
            System.out.println("\n\n Cannot perform the provisioning of the user " + userData.getUserId() + ": \n" + e.toString() + "\n\n");
        }

        return "problem";
    }
}

The Test:

@RunWith(SpringRunner.class)
public class ProvisionServiceTest {

    private ProvisionService provisionService;

    @MockBean
    private UsersRepo usersRepo;

    @Before
    public void setUp(){
        provisionService = new ProvisionService();
    }

     @Test
    public void performProvision_shouldPass() {
        UserData userData = new UserData("userid", 30, 1, "spot", 1);
        try {
            String result = provisionService.performProvision(userData);
            assertThat(result, is(equalTo("Success: User userid has been added to the database")));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
    }
}

EDIT 1:

Adding @Autowired and removing setUp() method results in the following:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.autoprovision.ProvisionServiceTest': Unsatisfied dependency expressed through field 'provisionService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.autoprovision.ProvisionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

like image 491
Darrel Holt Avatar asked Jun 30 '17 18:06

Darrel Holt


2 Answers

The given answer seems useful but just in case it can help someone, testing service is not so obvious in Spring (IMHO). The SpyBean annotation turns out to be really handy:

@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
    @SpyBean
    private ProvisionService provisionService;
}

Source : Spring Boot Reference - Testing

like image 27
Robin Avatar answered Oct 12 '22 21:10

Robin


As JB Nizet already stated, the UserRepo mock is not injected into the provisionService instance, because the provisionService instance is created in the setUp method with new.

Your test should look like this:

@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
    @Autowired // let Spring instantiate the instance to test
    private ProvisionService provisionService;

    @MockBean
    private UsersRepo usersRepo;

    @Test
    public void performProvision_shouldPass() {
        UserData userData = new UserData("userid", 30, 1, "spot", 1);

        String result = provisionService.performProvision(userData);
        assertThat(result, is(equalTo("Success: User userid has been added to the database")));
    }
}
like image 78
iBiber Avatar answered Oct 12 '22 22:10

iBiber