I'm trying to improve a unit test for a service I'm developing. I read somewhere that it's ideal to use #WebMvcTest annotation over #SpringBootTest when testing the Web or Controller layer.
However, for some reason, a #MockBean service field I am using in the Test class is always NULL.
java.lang.AssertionError: Expecting actual not to be null
In the test class below, serviceIsLoaded() method is always null when I run that single test.
SectionRESTControllerTest.java
#WebMvcTest
public class SectionRESTControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private SectionServiceImpl sectionServiceImpl;
#Test
public void serviceIsLoaded() {
assertThat(sectionServiceImpl).isNotNull();
}
}
SectionServiceImpl.java
#Service
public class SectionServiceImpl implements SectionService {
private final Logger logger = LoggerFactory.getLogger(SectionServiceImpl.class);
#Autowired
private SectionRepository sectionRepo; //saves to section table
#Autowired
private GradeLevelRepository gradeLevelRepo;
#Override
public Section createSection(Section section) {...}
#Override
public Section updateSection(Section request) throws Exception {...}
#Override
public Section getSectionById(Long id) {
return sectionRepo.findById(id).get();
}
#Override
public List<Section> getAllActiveSections() {
return sectionRepo.findSectionByIsActiveTrue();
}
#Override
public List<Section> getAllInActiveSections() {
return sectionRepo.findSectionByIsActiveFalse();
}
#Override
public List<Section> getSectionsByGradeLevelId(Long id) {
return sectionRepo.findByGradeLevelId(id);
}
#Override
public List<Section> getSectionByGradeLevelCode(String code) {
return sectionRepo.findByGradeLevelCode(code);
}
#Override
public List<Section> getSectionByGradeLevelCategory(String category) {
return sectionRepo.findByGradeLevelCategory(category);
}
}
My understanding is, with #WebMvcTest, it does not load the entire application context with all managed beans which makes the UnitTest run faster. Unlike, #SpringBootTest which loads everything when running the UnitTest.
SectionService.java
public interface SectionService {
Section createSection(Section section);
Section updateSection(Section section) throws Exception;
Section getSectionById(Long id);
List<Section> getAllActiveSections();
List<Section> getAllInActiveSections();
List<Section> getSectionsByGradeLevelId(Long id);
List<Section> getSectionByGradeLevelCode(String code);
List<Section> getSectionByGradeLevelCategory(String category);
}
Main class
#SpringBootApplication
public class AutoformSettingsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AutoformSettingsServiceApplication.class, args);
}
}
Do you have any thoughts or ideas why the #MockBean sectionServiceImpl is null
Thank you.
I m using mockito for junit. I have doubt while creating mock of object.
I have class called DBConnect. Where I need database properties like dbname, credentials etc.
This class is used by PatientDetails. Now when I am writing junit for PatientDetails. So I am using following code.
#RunWith(MockitoJUnitRunner.class)
public class PatientDetailsTest {
#Mock
DBConnect dbConnect
#Before
public void setUp()
{
PatientDetails testClass = new PatientDetails();
testClass.setDBConnect(dbConnect);
}
}
I can not get correct result with this.
You code seems fine to me. I've extended it slightly to include a test, so that it can be run. This works fine:
#RunWith(MockitoJUnitRunner.class)
public class PatientDetailsTest {
#Mock
DBConnect dbConnect;
#Before
public void setUp() {
when(dbConnect.sayHello()).thenReturn("works for me");
PatientDetails testClass = new PatientDetails();
testClass.setDBConnect(dbConnect);
}
#Test
public void testname() throws Exception {
System.out.println("foo");
}
private static interface DBConnect {
String sayHello();
}
private static class PatientDetails {
public void setDBConnect(DBConnect dbConnect) {
System.out.println(dbConnect.sayHello());
}
}
}
Output:
works for me
foo
I am trying to write a Jukito test that uses a GIN factory I created.
My factory looks like so:
public interface ClientFactory {
public DOMModel create(Entity ref);
}
I am binding it in my gin module like so:
public class ClientModule extends AbstractGinModule {
#Override
protected void configure() {
install(new GinFactoryModuleBuilder().build(ClientFactory.class));
}
}
DOMModel looks like so:
public class DOMModel {
...
#Inject
public DOMModel(CollabClientFactory collabFactory, #Assisted Entity ref, #Assisted Document domDoc){
this.colabClient = collabFactory.create("DOMMODEL:"+ref.getID(), "com.server.impl.DOMCollabSite.java", collaborator);
}
...
}
Then my test looks like this:
#RunWith(JukitoRunner.class)
public class Test {
public static class Module extends JukitoModule {
protected void configureTest() {
install(new GinModuleAdapter(new ClientModule()));
}
}
#Inject
ClientFactory modelFactory;
#Test
public void testSimple() throws Exception{
Entity entity = new Entity(){
#Override
public String getID() {
return "someID";
}
};
DOMModel model1 = modelFactory.create(entity);
assertNotNull(model1);
}
}
This test fails because model1 is null, however I get no other errors or warnings whatsoever. What is wrong?
I'm trying to mock a concrete Class using Mockito. However, it remains null in the service under test.
My concrete class and Service:
//My Concrete Class
#Component("supporter")
public class Supporter
{
#Autowired
private IDriver driver;
public int someMethod(int){...}
...
}
//Service Class that uses this abstract class
public class Service implements IService
{
private ExceptionHandler exceptionHandler;
#Autowired
public void setExceptionHandler(ExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
private Supporter supporter;
#Autowired
public void setSupporter(Supporter supporter) {
this.supporter = supporter;
}
public int hookItem(int arg)
{
...
//supporter is always null while mock testing <----
int count = supporter.someMethod(arg);
...
return count;
}
}
My Test Code :
public class ServiceTest extends AbstractTestMockito
{
...
IService service = null;
#Mock
private ExceptionHandler exceptionHandler;
#BeforeMethod
public void setup() {
service = new Service();
}
#Test(enabled=true)
public void shouldDoSomething()
{
Supporter supporter = Mockito.mock(Supporter.class);
given(supporter.someMethod(1)).willReturn(new Integer(10));
final int response = service.hookItem(1);
//Assert...
}
}
What could be the reason for it being null?
(My classes/service are Spring beans)
Looking at the test class, it seems like you you are not injecting the mocked Supporter instance into the service instance, e.g. try to add service.setSupporter(supporter); before calling service.hookItem(1).
Is there a way to get a class that extends AbstractTransactionalJUnit4SpringContexts to play nicely with JUnit's own #RunWith(Parameterized.class), so that fields marked as Autowired get wired in properly?
#RunWith(Parameterized.class)
public class Foo extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired private Bar bar
#Parameters public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Test public void someTest(){
bar.baz() //NullPointerException
}
}
See http://jira.springframework.org/browse/SPR-5292
There is a solution.
You can use a TestContextManager from Spring. In this example, I'm using Theories instead of Parameterized.
#RunWith(Theories.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class SeleniumCase {
#DataPoints
public static WebDriver[] drivers() {
return new WebDriver[] { firefoxDriver, internetExplorerDriver };
}
private TestContextManager testContextManager;
#Autowired
SomethingDao dao;
private static FirefoxDriver firefoxDriver = new FirefoxDriver();
private static InternetExplorerDriver internetExplorerDriver = new InternetExplorerDriver();
#AfterClass
public static void tearDown() {
firefoxDriver.close();
internetExplorerDriver.close();
}
#Before
public void setUpStringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Theory
public void testWork(WebDriver driver) {
assertNotNull(driver);
assertNotNull(dao);
}
}
I found this solution here : How to do Parameterized/Theories tests with Spring
You can use SpringClassRule and SpringMethodRule for this purpose
#RunWith(Parameterized.class)
#ContextConfiguration(...)
public class FooTest {
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private Bar bar
#Parameters
public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Test
public void someTest() {
bar.baz() //NullPointerException
}
}
No, you can't. The superclass has:
#RunWith(SpringJUnit4ClassRunner.class)
which assures that the tests are run within spring context. If you replace it, you are losing this.
What comes to my mind as an alternative is to extend SpringJunit4ClassRunner, provide your custom functionality there and use it with #RunWith(..). Thus you will have the spring context + your additional functionality. It will call super.createTest(..) and then perform additional stuff on the test.
I've had to handle the transactions programmatically (see http://www.javathinking.com/2011/09/junit-parameterized-test-with-spring-autowiring-and-transactions/):
#RunWith(Parameterized.class)
#ContextConfiguration(locations = "classpath*:/testContext.xml")
public class MyTest {
#Autowired
PlatformTransactionManager transactionManager;
private TestContextManager testContextManager;
public MyTest (... parameters for test) {
// store parameters in instance variables
}
#Before
public void setUpSpringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Parameterized.Parameters
public static Collection<Object[]> generateData() throws Exception {
ArrayList list = new ArrayList();
// add data for each test here
return list;
}
#Test
public void validDataShouldLoadFully() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
status.setRollbackOnly();
try {
... do cool stuff here
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
});
}
Here's how I made it work in Spring Boot 1.5.7:
Add the #RunWith(Parameterized.class) annotation to your class
Inject your dependency as class field with:
#Autowired
private Bar bar;
Add your parameter/s as class fields:
private final int qux;
private final Boolean corge;
private final String grault;
Add a constructor to initialize the parameter/s as follows:
public Foo(int qux, Boolean corge, String grault) throws Exception {
this.qux = qux;
this.corge = corge;
this.grault = grault;
new TestContextManager(getClass()).prepareTestInstance(this);
}
Add a static method data that returns a Collection containing the values of your parameters at each iteration, respecting the order by which they are passed to the constructor:
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ 1, Boolean.FALSE, "Hello" },
{ 2, Boolean.TRUE, null },
{ 3, null, "world" }
});
}
Write your test using the class fields declared above like follows:
#Test public void someTest(){
// Some arrangements
// Some actions
assertThat(myTestedIntValue, is(equalTo(qux));
assertThat(myTestedBooleanValue, is(equalTo(corge));
assertThat(myTestedStringValue, is(equalTo(grault));
}
Inspired by Simon's solution, you can use TestContextManager also with Parameterized runner:
#RunWith(Parameterized.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class MyTestClass {
#Parameters public static Collection data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Before
public void setUp() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
}
}
Here is full example
I am not sure about handling #Transactional in this case.