用模拟对象进行单元测试

时间:2010-02-13 19:33:35

标签: unit-testing mocking rhino-mocks

请查看以下article about testing with mocks

所以有一个使用模拟对象进行单元测试的例子。如您所见,测试是针对GetPersonByID方法编写的。在IPersonServices界面中还有另一种方法:List<Person> GetPersons();

有人能告诉我这个服务的Test方法应该如何使用模拟对象?例如,在GetPersons的情况下,其具有List类型。

2 个答案:

答案 0 :(得分:5)

使用Rhino.Mocks查找不同的单元测试示例会更好。这个例子嘲笑了实际的测试类,你永远不会这样做。

假设您有PersonRepository和PersonService。您希望对使用PersonRepository的PersonService进行单元测试。省略了人的实施。

 public interface IPersonService
 {
      Person GetPerson( int id );
      List<Person> GetPersons();
 }

 public class PersonRepository
 {
      public virtual GetPerson( int id )
      {
          ... implementation
      }

      public virtual GetPersons()
      {
          ... implementation
      }
 }


 public class PersonService : IPersonService
 {
     private PersonRepository Repository { get; set; }

     public PersonService() : this(null) { }

     public PersonService( PersonRepository repository )
     {
         this.Repository = repository ?? new PersonRepository();
     }

     public Person GetPerson( int id )
     {
         return this.Repository.GetPerson( id );
     }

     public List<Person> GetPersons()
     {
         return this.Repository.GetPersons();
     }
}

现在我们进行了单元测试,以确保服务正确调用存储库。

public void GetPersonTest()
{
     var repository = MockRepository.GenerateMock<PersonRepository>();

     var expectedPerson = new Person( 1, "Name" );

     repository.Expect( r => r.GetPerson( 1 ) ).Return( expectedPerson );

     var service = new PersonService( repository );

     var actualPerson = service.GetPerson( 1 );

     Assert.AreEqual( expectedPerson.ID, actualPerson.ID );
     Assert.AreEqual( expectedPerson.Name, actualPerson.Name );

     repository.VerifyAllExpectations();
}

public void GetPersonsTest()
{
     var repository = MockRepository.GenerateMock<PersonRepository>();

     var expectedPerson = new Person( 1, "Name" );

     var listOfPeople = new List<Person> { expectedPerson };

     repository.Expect( r => r.GetPersons() ).Return( listOfPeople );

     var service = new PersonService( repository );

     var actualList = service.GetPersons( );

     Assert.AreEqual( 1, actualList.Count );

     var actualPerson = actualList.First();

     Assert.AreEqual( expectedPerson.ID, actualPerson.ID );
     Assert.AreEqual( expectedPerson.Name, actualPerson.Name );

     repository.VerifyAllExpectations();
}

答案 1 :(得分:0)

作为tvanfosson said,这不是一个非常有用的例子。

以下是Rhino Mocks wiki的示例。

        [Test]
        public void SaveProjectAs_CanBeCanceled()
        {
            MockRepository mocks = new MockRepository();
            // projectView is the mock object
            IProjectView projectView = mocks.StrictMock<IProjectView>();
            Project prj = new Project("Example Project");
            // presenter is the object under test
            IProjectPresenter presenter = new ProjectPresenter(prj, projectView);

            // set expectations on the mock object
            Expect.Call(projectView.Title).Return(prj.Name);
            Expect.Call(projectView.Ask(question, answer)).Return(null);
            mocks.ReplayAll();

            // now execute the test
            Assert.IsFalse(presenter.SaveProjectAs());
            mocks.VerifyAll();
        }

我认为从模拟方法调用返回List类型没有什么特别之处。只是设定正常的期望。在上面的示例中,如果Ask()方法返回了字符串列表,Return()之后的Expect.Call(...Ask...)方法将获取字符串列表。这是关于记录/重放模拟和泛型组合的可爱之处,您的期望内置了类型安全性。比早期的模拟对象库更好,您可以在字符串中使用方法名称定义所有内容并返回所有返回值只是对象。

有关该示例的更多说明以及许多其他示例,请查看Rhino Mocks wiki