unit testing mock injection - java

I am trying to unit test my class, and mock the DAO to provide predictable results. Still, it would appear that my DAO's method is still being called as I receive a hibernate error.
org.hibernate.exception.GenericJDBCException: Station TST not found.
This error is a result of my database not containing TST, but shouldnt this not even be called since I mocked the DAO? How do I mock the call so that the database isn't even hit.
Here's how I set up my mock
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class MyServiceTest{
#Autowired
private MyService service;
private MyDAO dao;
private LinkedList objs;
#Before
public void init() throws SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
// mock the dao for predictable results
dao = mock(MyDAO.class);
when(dao.myDBCall(anyString(), any(Date.class))).thenReturn(legs);
Field f = MyService.class.getDeclaredField("dao");
f.setAccessible(true);
f.set(service, dao);
}
#Test
public void testCall() {
// construct our sample leg data
legs = new LinkedList();
//fill in my stub data i want to return
Collections.shuffle(legs);
List results = service.testingCall("TST", new Date()); // this fails because service is using the dao, but it is making a call to the DB with this garbage 'Test' param rather than just returning 'legs' as stated in my when clause
assertThat(results, not(nullValue()));
}
#Test
public void testGetGates() {
// fail("Not yet implemented");
}
#Test
public void testGetStations() {
// fail("Not yet implemented");
}
}

I think that your Service is instantiated by spring with your Dao defined in your application-context.xml and you get your error before you even try to inject your mock in your service.
One thing I like to use to test my services is an Autowired constructor and then in my tests I do not instantiate my services by spring but using the constructor and the mock.
private MyDao myDao;
#Autowired
public MyService(MyDao myDao){
this.myDao = myDao;
}
And then in your test :
MyService myService = new Myservice(mockedDao);

For first, instead of Field f = MyService.class.getDeclaredField("dao"); check for PowerMock (check for Whitebox)
Mocking one object will not prevent hibernate to start (because you are loading applicationContext.xml, so hibernate will try to connect to DB). Your mock - it is just a POJO at one field of one test instance, not a Spring bean or replacement for class.
If you want to test only dao and service classes (create clear unit test) - remove Spring related annotations from test and do it on your own (create mock, create service, put mock to service, and test it).
If you want test your application with Spring context (create integration test) - create H2 in-memory database for hibernate and just test your service (don't forget to clear it in #After).
Third way - split your configuration file into two Spring profiles (for example dev and test) and implement mock yourself (put mock to test, real hibernate and dao to dev).
If you dont want use Spring profiles - it is possible to split applicationContext.xml into 3 files (for common beans, for real DB beans, for mocks).
And one more sexy way - use springockito-annotations (but you still need to avoid hibernate be loaded)

Related

Integration test a manual transaction with transaction template

I am getting null pointer exceptions on my transaction template when I try to test my method that uses manual transactions. When I am running the application in Spring Boot it works as expected.
#Autowired
TransactionTemplate template;
public CompletableFuture<MyResultEntity> addToA(BInput input) {
return CompletableFuture
.supplyAsync(
() -> template.execute(status -> {
A a = aRepository.findOne(input.getA());
List<B> addedBs = saveBs(input.getB(), a);
return new MyResultEntity(a, addedBs);
}), MyCustomExecutor());
}
I have tried using a mock template and inject it like this:
#Mock
private TransactionTemplate transactionTemplate;
#InjectMocks
private MyClass myClass;
I have also tried annotating my test with:
#RunWith(SpringJUnit4ClassRunner.class)
When debugging this configuration the template is actually injected and is not null any more. But since I am interested in testing the actions in the transactions I do not wish to mock it so i use:
when(transactionTemplate.execute(Mockito.any())).thenCallRealMethod();
This throws a new null pointer exception though since the transaction template tries to use the TransactionManager and that is still null.
How can I unit test my method calls inside the the transaction template?
What I normally do is not to call the real method, but to just mock the real behavior instead. Calling the real method in the mock will fail, because a mock is not managed inside of springs injection context. Well, to be exact, you can make them exist inside the injection context by adding them to a test configuration (plain SpringMVC) or using #MockBean (spring boot). But still they are just injected as a dependency. But won't receive any dependencies. For unit tests this is most often the desired behavior.
So just do something like:
when(_transactionTemplate.execute(any())).thenAnswer(invocation -> invocation.<TransactionCallback<Boolean>>getArgument(0).doInTransaction(_transactionStatus));
_transactionStatus can be a mock itself to test the usage of the state inside the callback.
Mocking is what mocks are used for :)
If TransactionManager is null it means that Spring probably didn't load all necessary dependencies in the test context.
Anyway, why mocking the TransactionTemplate if you need to invoke the execute() method ?
Your test looks like an integration/sociable test and not an unit test.
If it is the case, you don't need to mock anything.
If you want to write an unit test that tests the actual logic in the addToA() method, you should use mock without partial mocking.
Mock dependencies used in the Supplier provided and assert that the expected MyResultEntity instance is returned.
Note that your unit test will have a limited value and may be considered as brittle as it asserts only that a series of method was invoked. Generally you want to assert a behavior in terms of more concrete logic such as computation/extraction/transformation.
Here is an example (no tested but it should give an idea on the way) :
#Mock
Repository ARepositoryMock;
#Mock
Repository BRepositoryMock;
#Test
public void addToA() throws Exception {
BInput input = new BInput();
// record mock behaviors
A aMockByRepository = Mockito.mock(A.class);
List<B> listBMockByRepository = new arrayList<>();
Mockito.when(ARepositoryMock.findOne(input.getA())).thenReturn(aMockByRepository);
Mockito.when(BRepositoryMock.saveBs(input.getB(), aMockByRepository)).thenReturn(listBMockByRepository);
// action
CompletableFuture<MyResultEntity> future = myObjectUnderTest.addToA(input);
//assertion
MyResultEntity actualResultEntity = future.get();
Assert.assertEquals(aMockByRepository, actualResultEntity.getA());
Assert.assertEquals(listBMockByRepository, actualResultEntity.getListOfB());
}

Junit method invocation fails due to spring injection

I have written Junit test class to test particular method. One of the variables being processed in this method is spring injected, by taking the value from properties file.
Below is my test method
#Test
public void myTestMethod() {
//invoking the method to be tested
Assert.assertTrue(updateGroceries());
}
This is the class to be tested,
public class ToBeTested {
//Spring injected value
String categories;
public boolean updateGroceries() {
List<String> categoryList = StringUtils.convertStringToList(categories);
}
In the above class, categories variable is spring injected.
This is properties file content:
categories = Dals,Pulses,Dry Fruits,Edible Oil
Now while running my Junit method, execution is failing because dependency injection is failing.Since the code I want to test runs on tomcat. I want to test the code without running tomcat. Please suggest some solution.
First of all to run mockito you need to enable it over your test.
Using annotation #RunWith(MockitoJunitRunner.class) or execute at the beginning of your test Mockito.initMocks().
Then your test should look like:
#RunWith(MockitoJunitRunner.class)
private YourTest{
#InjectMocks
ToBeTested toBeTested;
#Mock
ToBeTestedDependency dependency;
#Before
public void setUp(){
ReflectionTestUtils.setField(toBeTested, "categories",
"someCategory");
}
#Test
public void shouldDoThisOrThat(){
toBeTested.updateCategories();
}
}
Unfortunately mockito doesn't support injecting #Valueannotated field. You need to use ReflectionTestUtils or setup run your test with SpringJUnit4ClassRunner where you need to define your spring context with PropertyPlaceholder configuration to resolve property that you have as your Value key. There you can find reference to documentation and example of spring testing approach.
Hope this helped.
You should look at Mockito. When you use mockito framework, you can create mocks for spring injected values. You should read more on mockito website.

Testing Hibernate DAO using Junit

I am using a combination of Spring and Hibernate in my project and would like to test the DAO methods like Save and Delete methods.
daoFoundation is a wrapper class created over hibernateSession.
#Override
public String createSubject(Subject subject) {
String subjectId = (String) daoFoundation.save(subject);
return subjectId;
}
This is what I wrote in my JUnit Runs with SpringJunit4ClassRunner
I created the subject object in my SetupMethod.
#Test
public void createSubjectTest(){
subjectDao.createSubject(subject);
assertNotNull(hassSubjectSelection.getId());
}
Is this sufficient or do I need to write anything additional in my test class?
The easiest way is to import your Spring application context, autowire in the DAO's you want to test and then mark either your test methods or the entire class as #Transactional. This will create a Hibernate session, run your test and then automatically roll back the transaction so you don't effect your database state with your tests.
Have a look at how to run unit tests with Spring here. You can get Spring to create your entire application context using the #ContextConfiguration annotation. So if you create your database using an XML file called database-servlet.xml then you would annotate
#ContextConfiguration(locations={"classpath:/database-servlet.xml"})
public class Test()
You can use the annotation #RunWith(SpringJUnit4ClassRunner.class) to use functionality of the Spring TestContext Framework with your unit tests. This allows you to do things like declare expected exceptions that should be thrown, run timed tests, repeat test runs X times and a bunch of other cool stuff.
Basically to get this working, your test class should look similar to the following:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={YOUR APP CONTEXT FILES HERE AS A COMMA SEPARATED LIST})
public class Test(){
#Autowired
private YourDAO yourDAO;
#Test
#Transactional
public void testSave(){
//Test save method here. Any database changes made here will be
//automatically rolled back when the test finishes.
}
Let me know if that works or not.
The best way to test your dao layer is to use the spring jdbctemplate to write data to your database the test your get and delete methods. Then in the #after delete the records you wrote. Then use hibernate to write to your database and use jdbctemplate to read them back. Then delete your test rows. Anything less and all you are really doing is testing hibernate's caching.

Arquillian + TestNG: How to access container managed objects in #Before/#After methods?

I couldn't find any satisfying solution for this problem, though other people have encountered it before...
I'd like to test a business bean which modifies persistent data using a dao.
The dao can be injected into the test methods as it is an ejb.
How to make it available in typical #Before/#After methods, for example to clean up the db.
Brief Example:
#PersistenceTest
public class MyTestClass extends Arquillian {
#Inject private Dao dao;
#Inject private MyBean myBean;
#BeforeMethod
public void cleanDB () {
dao.remove(foo); // Currently throws NPE as dao is not injected.
}
#Test
public void someTest () {
// In a Test-method dao is available and calling cleanDB from here also
// works as intended....
}
}
As far as I know only the Test-methods are executed in the container. Most information that I found seems to be outdated.
Is there any nice way to achieve this?
Thank you!
I'm using (managed) Wildfly 8 as app server.
Arquillan invokes the #Before** and #After** methods twice.
Once in client mode, once in container mode.
The only solution I found so far is, that you must verify that the dao was injected before you use it like :
#BeforeMethod
public void cleanDB () {
if (dao != null) {
dao.remove(foo);
}
}
So if you make a breakpoint and runs your code you should have 2 invokations of this method:
1st: dao is null
2nd: dao is injected
Hope that helps.
See also http://jayshaughnessy.blogspot.de/2012/11/arquillian-and-testng.html for more information.

Mocking local object created by spring application context using Mockito

I am trying to mock a local object, using Mockito Framework, that is being created from the spring application context; But every time I run the application its fails to replace the original object with the mocked object.
Here is the original class's code spinets:
public void executeMyJob(){
ApplicationContext springContext = ApplicationContextUtil.getApplicationContext();
MusicEAO music= (MusicEAO) springContext.getBean("MusicEAO");
List<Brand> dataList =music.getAll();
......
}
I want to mock the MusicEAO so when the getAll() method is called, it will use the mock object.
Below is my test class code snippets:
#Mock
MusicEAO musicEAO;
when(musicEAO.findAll()).thenReturn(myDefinedList);
How can I resolve this issue?
It's hard to tell from the cod you posted but the problem might be that you are mocking MusicEAO in your test but the code you are executing is using a Spring ApplicationContext to get a reference to the MusicEAO bean.
Your original class should not use MusicEAO music= (MusicEAO) springContext.getBean("MusicEAO"); but instead have the bean injected by Spring using #Autowired through a constructor or a setter method (or other dependency injection method). You test will then be able to easily inject a mock version.
class MyJobClass {
MusicEAO music;
#Autowired
public MyJobClass(MusicEAO musicEao) {
this.music = musicEao;
}
public void executeMyJob(){
List<Brand> dataList =music.getAll();
......
}
}
When you say
every time I run the application it fails to replace the original
object with the mocked object
You shouldn't have to run the application to run a unit test for this class - are you asking how to inject mocks into a running application?
.
It doesn't work this way. In your current code :
The following instance is the one in your test :
#Mock MusicEAO musicEAO;
But in your production code, you are using Spring to acquire the Music instance :
MusicEAO music= (MusicEAO) springContext.getBean("MusicEAO");
Nowhere you seem to say to spring that you want the Music mock to be affected to MusicEAO bean name.
If you are doing a Unit Test I would recommand you to avoid messing with Spring, if that's an integration test, then you'll have to find a way to create the mock and pass it over to spring.
For example you can create the mock in the Spring context, autowire it in your test.
Also, I wouldn't recommand the use of static calls in this situation to acquire the Spring context in order to finaly get a hold on the Music object. it makes me think of Spring as a registry which isn't really the case. Spring is a container. Instead you should try to refactor your code in such a way that the Music bean is wired (#Autowired, setters, etc.) in ExecutionJob.
Then it would be even easier to write a Unit Test with JUnit and Mockito, with annotations like #Mock and #InjectMocks.
Hope that helps.

Categories

Resources