3

Person.java

public class Person
{
    private final Integer personID;
    private final String personName;
    public Person( Integer personID, String personName )
    {
        this.personID = personID;
        this.personName = personName;
    }
    public Integer getPersonID()
    {
        return personID;
    }
    public String getPersonName()
    {
        return personName;
    }
} 

PersonDAO.java

public interface PersonDao
{
    public Person fetchPerson( Integer personID );
    public void update( Person person );
} 

**PersonService.java** 

public class PersonService
{
    private final PersonDao personDao;
    public PersonService( PersonDao personDao )
    {
        this.personDao = personDao;
    }
    public boolean update( Integer personId, String name )
    {
        Person person = personDao.fetchPerson( personId );
        if( person != null )
        {
            Person updatedPerson = new Person( person.getPersonID(), name );
            personDao.update( updatedPerson );
            return true;
        }
        else
        {
            return false;
        }
    }
} 

PersionServiceTest.java

public class PersonServiceTest
{
    @Mock
    private PersonDao personDAO;
    private PersonService personService;
    @Before
    public void setUp()
        throws Exception
    {
        MockitoAnnotations.initMocks( this );
        personService = new PersonService( personDAO );
    }
    @Test
    public void shouldUpdatePersonName()
    {
        Person person = new Person( 1, "Phillip" );
        when( personDAO.fetchPerson( 1 ) ).thenReturn( person );
        boolean updated = personService.update( 1, "David" );
        assertTrue( updated );
        verify( personDAO ).fetchPerson( 1 );
        ArgumentCaptor<Person> personCaptor = ArgumentCaptor.forClass( Person.class );
        verify( personDAO ).update( personCaptor.capture() );
        Person updatedPerson = personCaptor.getValue();
        assertEquals( "David", updatedPerson.getPersonName() );
        // asserts that during the test, there are no other calls to the mock object.
        verifyNoMoreInteractions( personDAO );
    }
    @Test
    public void shouldNotUpdateIfPersonNotFound()
    {
        when( personDAO.fetchPerson( 1 ) ).thenReturn( null );
        boolean updated = personService.update( 1, "David" );
        assertFalse( updated );
        verify( personDAO ).fetchPerson( 1 );
        verifyZeroInteractions( personDAO );
        verifyNoMoreInteractions( personDAO );
    }
} 

/* In the above example mocked personDAO object is sent to the personService class object through the constructor of the personService(in personServiceTest class).

My doubt is how to pass the mocked personDAO object to the personService class if it is not having any setter or a constructor?

i.e what if the personDAO is created using "new" instead of getting from the constructor or setter in the personService class like mentioned in the below code .*/

public class PersonService
{
    private final PersonDao personDao=new PersonDao();

    public boolean update( Integer personId, String name )
    {
        Person person = personDao.fetchPerson( personId );
        if( person != null )
        {
            Person updatedPerson = new Person( person.getPersonID(), name );
            personDao.update( updatedPerson );
            return true;
        }
        else
        {
            return false;
        }
    }
} 

How about using reflectiontestutils.setfield();

Sai Surya Kattamuri
  • 1,046
  • 12
  • 22

4 Answers4

1

Using Mockito, you can do that by using @Mock and @InjectMocks and the MockitoJUnitRunner.

This question describes this: Using @Mock and @InjectMocks

Community
  • 1
  • 1
Benjamin
  • 1,816
  • 13
  • 21
1

Through my substantial searches on Mockito I found there are two types of mocking:

  1. Proxy Mocking (Usual stubbing)
  2. Class remapping(Only Jmockit supports)

You can read about "How Mock Objects Work" here.

For my question, Class Remapping was the solution

Another solution is through the use of InjectMocks and ReflectionTestUtils

/* We can place this code in the JUnit test Class */
@Mock
PersonDAO personDAO;

@InjectMocks
PersonService personService;

@Before
public void setUP() {
    MockitoAnnotations.init(this);
}

@Test
public void shouldUpdatePersonName(){ 
    ReflectionTestutils.setField(personService,"personDao",personDAO);
    ............Remaining Code..........
}

What ReflectionTestUtils does is it will replace the personDao(created using "new" operator) present in the personService object with the locally created(using @Mock) mock personDAO.

ReflectionTestutils.setField(target,"name",actual);

There is a wealth of information beyond what I can give here about ReflectionTestUtils on the net.

ethesx
  • 1,339
  • 5
  • 19
  • 35
Sai Surya Kattamuri
  • 1,046
  • 12
  • 22
1

Just for the record, here is what the test class looks like with JMockit 1.12:

public class PersonServiceTest
{
    @Tested PersonService personService;
    @Mocked PersonDao personDAO;

    @Test
    public void shouldUpdatePersonName()
    {
        final Person person = new Person(1, "Phillip");

        new NonStrictExpectations() {{
            personDAO.fetchPerson(1); result = person; times = 1;
        }};

        boolean updated = personService.update(1, "David");

        assertTrue(updated);

        new FullVerifications() {{
            Person updatedPerson;
            personDAO.update(updatedPerson = withCapture());
            assertEquals("David", updatedPerson.getPersonName());
        }};
    }

    @Test
    public void shouldNotUpdateIfPersonNotFound()
    {
        new Expectations() {{ personDAO.fetchPerson(1); result = null; }};

        boolean updated = personService.update(1, "David");

        assertFalse(updated);
    }
}
Rogério
  • 16,171
  • 2
  • 50
  • 63
0

I think your tests are telling you that database records are hard to implement as unmodifiable objects.

How about adding

Person updateName(String name);

to Person class?