描述

BDD

given some preconditions (Arrange)
when an action occurs (Act)
then verify the output (Assert)

行为驱动开发

  1. given(Arrange): 布置环境
  2. when(Act): 表演
  3. then(Assert): 然后检查

Code

准备相关类

public class PhoneBookRepository {
private final HashMap<String, String> mHashMap = new HashMap<>();

public boolean contains(String name) {
return mHashMap.containsKey(name);
}

public void insert(String name, String phone) {
mHashMap.put(name, phone);
}

public String getPhoneNumberByContactName(String name) {
return mHashMap.get(name);
}
}
public class PhoneBookService {
private final PhoneBookRepository phoneBookRepository ;

public PhoneBookService(PhoneBookRepository phoneBookRepository) {this.phoneBookRepository = phoneBookRepository;}

public void register(String name, String phone) {
if (!name.isEmpty() && !phone.isEmpty()
&& !phoneBookRepository.contains(name)) {
phoneBookRepository.insert(name, phone);
}
}

public String search(String name) {
if (!name.isEmpty() && phoneBookRepository.contains(name)) {
return phoneBookRepository.getPhoneNumberByContactName(name);
}
return null;
}
}


BDD风格的测试

@RunWith(JUnit4.class)
public class PhoneBookServiceTest {
private PhoneBookRepository phoneBookRepository;
private String momContactName;
private PhoneBookService phoneBookService;
private String momPhoneNumber;

@Before
public void before() {
momContactName = "Hello";
momPhoneNumber = "123";
phoneBookRepository = mock(PhoneBookRepository.class);
phoneBookService = new PhoneBookService(phoneBookRepository);
}

@Test
public void testBDD() {
given(phoneBookRepository.contains(momContactName))
.willReturn(false);

phoneBookService.register(momContactName, momPhoneNumber);

then(phoneBookRepository)
.should()
.insert(momContactName, momPhoneNumber);
}


mock返回值

  @Test
public void returnValue() {
given(phoneBookRepository.contains(momContactName))
.willReturn(false);

String xContactName = "Hello";
phoneBookService.register(xContactName, "");

then(phoneBookRepository)
.should(never())
.insert(momContactName, momPhoneNumber);
}


mock动态返回值

  @Test
public void returnDynamic() {
given(phoneBookRepository.contains(momContactName))
.willReturn(true);
given(phoneBookRepository.getPhoneNumberByContactName(momContactName))
.will((InvocationOnMock invocation) ->
invocation.getArgument(0).equals(momContactName)
? momPhoneNumber
: null);
phoneBookService.search(momContactName);
then(phoneBookRepository)
.should()
.getPhoneNumberByContactName(momContactName);
}


mock抛异常

  @Test
public void testException() {
String xContactName = "hahha";
given(phoneBookRepository.contains(xContactName))
.willReturn(false);
String tooLongPhoneNumber = "111111111111";
willThrow(new RuntimeException())
.given(phoneBookRepository)
.insert(any(String.class), eq(tooLongPhoneNumber));

try {
phoneBookService.register(xContactName, tooLongPhoneNumber);
fail("Should throw exception");
} catch (RuntimeException ignore) {
}

then(phoneBookRepository)
.should(never())
.insert(momContactName, tooLongPhoneNumber);
}
}


注意​​willThrow​​放在​​given​​前面了,因为​​given​​要mock的方法是void的,无法捕获