如何将模拟对象传递给没有该变量的setter或构造函数的类



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 );
    }
} 

/*在上面的示例中,模拟的personDAO对象通过personService的构造函数(在personServiceTest类中)发送到personService类对象。

我的疑问是,如果没有任何setter或构造函数,如何将模拟的personDAO对象传递给personService类?

也就是说,如果personDAO是使用"new"创建的,而不是像下面代码中提到的那样从personService类中的构造函数或setter中获取。*/

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;
        }
    }
} 

如何使用reflectiontestutils.setfield();

使用Mockito,可以通过使用@Mock@InjectMocksMockitoJUnitRunner来实现。

这个问题描述如下:使用@Mock和@InjectMocks

记录一下,以下是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);
    }
}

通过对Mockito的大量搜索,我发现有两种类型的嘲讽:

  1. 代理模拟(通常的存根)
  2. 类重新映射(只有Jmockit支持)

你可以在这里阅读"模拟对象是如何工作的"。

对于我的问题,类重映射是的解决方案

另一种解决方案是通过使用InjectMocksReflectionTestUtils

/* 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..........
}

ReflectionTestUtils的作用是将personService对象中的personDao(使用"new"运算符创建)替换为本地创建的(使用@Mock)mock personDAO

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

除了我能在网上提供的关于ReflectionTestUtils的信息之外,还有很多信息。

我认为您的测试告诉您,数据库记录很难实现为不可修改的对象。

添加怎么样

Person updateName(String name);

到Person类?

相关内容

  • 没有找到相关文章

最新更新