Fakes,Mocks,Stubs的区别

Fakes,Mocks,Stubs的区别

首先,本节的内容有一点偏理论,而且代码也不一定是用js来说明的,其次,理论的作用在于指导实践,因此我们后期的可测试js很多代码都会用到今天的理论知识,好了,开始吧。

1、Fake

Fakes are objects that have working implementations, but not same as production one. Usually they take some shortcut and have simplified version of production code.

Fake 是那些包含了生产环境下具体实现的简化版本的对象。

Fake 可以是某个 Data Access Object 或者 Repository 的基于内存的实现;该实现并不会真的去进行数据库操作,而是使用简单的 HashMap 来存放数据。这就允许我们能够在并没有真正启动数据库或者执行耗时的外部请求的情况下进行服务的测试。

@Profile("transient")
public class FakeAccountRepository implements AccountRepository {

   Map<User, Account> accounts = new HashMap<>();

   public FakeAccountRepository() {
       this.accounts.put(new User("john@bmail.com"), new UserAccount());
       this.accounts.put(new User("boby@bmail.com"), new AdminAccount());
   }

   String getPasswordHash(User user) {
       return accounts.get(user).getPasswordHash();
   }
}

2、Stub

Stub is an object that holds predefined data and uses it to answer calls during tests. It is used when we cannot or don’t want to involve objects that would answer with real data or have undesirable side effects.

Stub代指那些包含了预定义好的数据并且在测试时返回给调用者的对象。Stub常被用于我们不希望返回真实数据或者造成其他副作用的场景。

public class GradesService {

   private final Gradebook gradebook;

   public GradesService(Gradebook gradebook) {
       this.gradebook = gradebook;
   }

   Double averageGrades(Student student) {
       return average(gradebook.gradesFor(student));
   }
}

测试代码如下:

public class GradesServiceTest {

   private Student student;
   private Gradebook gradebook;

   @Before
   public void setUp() throws Exception {
       gradebook = mock(Gradebook.class);
       student = new Student();
   }

   @Test
   public void calculates_grades_average_for_student() {
       when(gradebook.gradesFor(student)).thenReturn(grades(8, 6, 10)); 
	   //stubbing gradebook

       double averageGrades = new GradesService(gradebook).averageGrades(student);

       assertThat(averageGrades).isEqualTo(8.0);
   }
}

3、Mock

Mocks are objects that register calls they receive. In test assertion we can verify on Mocks that all expected actions were performed.

Mocks指那些仅记录它们的调用信息的对象,在测试断言中我们需要验证 Mocks是否被进行了符合期望的调用。

public class SecurityCentral {

   private final Window window;
   private final Door door;

   public SecurityCentral(Window window, Door door) {
       this.window = window;
       this.door = door;
   }

   void securityOn() {
       window.close();
       door.close();
   }
}

测试代码如下:

public class SecurityCentralTest {

   Window windowMock = mock(Window.class);
   Door doorMock = mock(Door.class);

   @Test
   public void enabling_security_locks_windows_and_doors() {
       SecurityCentral securityCentral = new SecurityCentral(windowMock, doorMock);

       securityCentral.securityOn();

       verify(doorMock).close();
       verify(windowMock).close();
   }
}

这里解释一下:

securityOn 方法执行之后,windowdoor Mock对象已经记录了所有的交互信息,这就允许我们能够去验证 WindowDoor 是否被真实的调用。或许有人会疑问是否在真实环境下门与窗是否被真的关闭了?其实我们并不能保证,不过这也不是我们关注的点,也不是 SecurityCentral 这个类关注的目标。门与窗是否能被正常的关闭应该是由 DoorWindow这两个类所关注的。

简单来说,这个测试方法关注的是securityOn()这个方法的逻辑,而不关注WindowDoor这两个类逻辑。同时这样写的好处将不同类的功能进行了隔离,方便了代码的测试和提高了代码的重用。

 

 

版权声明:著作权归作者所有。

thumb_up 0 | star_outline 0 | textsms 0