Колмогорцев Дмитрий / dkolmogortsev@naumen.ru
Проверить, что багов нет!
А вот и нет!
package org.testingtalk.account;
public class AccountInfoService
{
...
public AccountInfo createNewAccountInfo(){
AccountInfo newInfo = new AccountInfo(idSequence.getAndIncrement());
accountsData.put(newInfo.getAccountId(), newInfo);
return newInfo;
}
...
}
public static void main(String[] args)
{
//Подготовка
AccountInfoService service = new AccountInfoService();
//Действия
AccountInfo info = service.createNewAccountInfo();
//Проверка
assert 0 == info.getBalance();
}
public class CalculatorTest {
@Test
public void testMultiply(){
Assert.assertEquals(4, new Calculator().multiply(2,2));
}
}
import static org.junit.Assert.*;
import org.junit.Test;
public class AccountInfoTest {
@Test
public void testNewInfoBalanceIsZero(){
//Подготовка
AccountInfoService service = new AccountInfoService();
//Действия
AccountInfo newInfo = service.createNewAccountInfo();
//Проверка
String message = "Balance is non zero"
assertEquals(message,0, newInfo.getBalance());
}
}
public class BaseTest{
@BeforeClass //Действия перед запуском класса
public static void setupClass() {}
@Before //Действия перед зауском теста
public void setup() {}
@After //Действия после завершения теста
public void tearDown() {}
@AfterClass //Действия после завершения тестового класса
public void tearDownClass() {}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Test {
//Какой Exception мы ожидаем при тесте
Class<? extends Throwable> expected() \
default Test.None.class;
long timeout() default 0L; //Таймаут выполнения теста
public static class None extends Throwable {
private static final long serialVersionUID = 1L;
private None() {
}
}
}
public class AccountInfoServiceTest {
private AccountInfoService service;
@Before
public void setup(){
this.service = new AccountInfoService();
}
@Test(expected = IllegalArgumentException.class)
public void testErrorWhenLoadNull(){
this.service.getInfo(null);
}
@Test(timeout = 1000)
public void testLoadWithinASecond(){
this.service.get(1);
}
}
public class TransferService
{
...
public void makeTransfer(long sourceAccount,
long targetAccount,
double moneyAmount)
{
//Проверить аккаунт источник
//Проверить целевой аккаунт
//Проверить сумму перевода
//Проверить наличие суммы у аккаунта источника
//Выполнить перевод
}
...
}
public class TransferService
{
private final AccountInfoService accountInfoService;
private final TransferLogService logService;
private int successFullTransfers = 0;
private int failedTransfers =0;
...
}
public class TransferService
{
...
public TransferService(AccountInfoService accountInfoService,
TransferLogService logService)
{
this.accountInfoService = accountInfoService;
this.logService = logService;
}
...
}
public class TransferService
{
...
public void makeTransfer(long sourceAccount,
long targetAccount,
double moneyAmount)
{
//Проверить аккаунт источник
if(sourceAccount <= 0){
throw new IllegalArgumentException("Invalid source account id: "
+ sourceAccount);
}
//Проверить целевой аккаунт
//Проверить сумму перевода
//Проверить наличие суммы у аккаунта источника
//Выполнить перевод
}
...
}
public class TransferService
{
...
public void makeTransfer(long sourceAccount,
long targetAccount,
double moneyAmount)
{
//Проверить аккаунт источник
//Проверить целевой аккаунт
if(targetAccount <= 0){
throw new IllegalArgumentException("Invalid target account id: "
+targetAccount);
}
//Проверить сумму перевода
//Проверить наличие суммы у аккаунта источника
//Выполнить перевод
}
...
}
public class TransferService
{
...
public void makeTransfer(long sourceAccount,
long targetAccount,
double moneyAmount)
{
//Проверить аккаунт источник
//Проверить целевой аккаунт
//Проверить сумму перевода
if(moneyAmount <= 0){
throw new IllegalArgumentException("Non positive transfer amount
is specified");
}
//Проверить наличие суммы у аккаунта источника
//Выполнить перевод
}
...
}
public class TransferService
{
...
public void makeTransfer(long sourceAccount, long targetAccount, double moneyAmount)
{
//Проверить аккаунт источник
//Проверить целевой аккаунт
//Проверить сумму перевода
//Проверить наличие суммы у аккаунта источника
AccountInfo fromAccountInfo = accountInfoService.getInfo(sourceAccount);
if (fromAccountInfo.getCurrentBalance() < moneyAmount)
{
throw new UnsupportedOperationException("Not enough credit balance");
}
//Выполнить перевод
}
...
}
public class TransferService
{
...
public void makeTransfer(long sourceAccount, long targetAccount, double moneyAmount)
{
...
//Выполнить перевод
try
{
performTransfer(sourceAccount, targetAccount, moneyAmount, fromAccountInfo);
logService.logTransfer(sourceAccount, targetAccount, moneyAmount);
successFullTransfers++;
}
catch (Exception e)
{
failedTransfers ++;
e.printStackTrace();
}
}
}
@Test
public void transferTest(){
//Подготовка
AccountInfoService service = new AccountInfoServiceImpl();
AccountInfo sourceInfo = service.createNewAccountInfo();
service.updateBalance(sourceInfo.getAccountId(), 10.0);
AccountInfo targetInfo = service.createNewAccountInfo();
TransferService transferService = new TransferService(service,
new TransferLogService());
...
}
@Test
public void transferTest(){
...
//Действия
transferService.makeTransfer(sourceInfo.getAccountId(), targetInfo.getAccountId(), 5.0);
...
}
@Test
public void transferTest(){
...
//Проверки
Assert.assertEquals(1, transferService.getSuccessFullTransfers());
Assert.assertEquals(5.0,
service.getInfo(sourceInfo.getAccountId()).getCurrentBalance(), 0.0);
Assert.assertEquals(5.0,
service.getInfo(targetInfo.getAccountId()).getCurrentBalance(), 0.0);
}
@Test
public void transferTest(){
//Подготовка
AccountInfoService service = new AccountInfoServiceImpl();
AccountInfo sourceInfo = service.createNewAccountInfo();
service.updateBalance(sourceInfo.getAccountId(), 10.0);
AccountInfo targetInfo = service.createNewAccountInfo();
TransferService transferService = new TransferService(service, new TransferLogService());
//Действия
transferService.makeTransfer(sourceInfo.getAccountId(), targetInfo.getAccountId(), 5.0);
//Проверки
Assert.assertEquals(1, transferService.getSuccessFullTransfers());
Assert.assertEquals(5.0, service.getInfo(sourceInfo.getAccountId()).getCurrentBalance(), 0.0);
Assert.assertEquals(5.0, service.getInfo(targetInfo.getAccountId()).getCurrentBalance(), 0.0);
}
public class AccountInfoStub implements AccountInfoService
{
private final static AccountInfo STUB = new AccountInfo(999, 10.00);
private final static AccountInfoStub INSTANCE = new AccountInfoStub();
private AccountInfoStub() { }
public static AccountInfoStub get() { return INSTANCE; }
@Override
public AccountInfo createNewAccountInfo() { return STUB.clone(); }
...
@Override
public AccountInfo getInfo(long id) { return STUB.clone(); }
}
@Test
public void testSuccessfullTransfers() throws Exception
{
TransferService transfers = new TransferService(AccountInfoStub.get(), new TransferLogService());
transfers.makeTransfer(1, 2, 2.0);
Assert.assertEquals(1, transfers.getSuccessFullTransfers());
}
@Test
public void testTransferLogged(){
//Подготовка
TransferLogService mockedLogService = Mockito.mock(TransferLogService.class);
TransferService transfers = new TransferService(AccountInfoStub.get(), mockedLogService);
//Действия
transfers.makeTransfer(1, 2, 2.0);
//Проверка
//Проверяем, что метод logTransfer вызвался единожды с аргументами 1, 2, 2.0
Mockito.verify(mockedLogService, Mockito.times(1)).logTransfer(1,2,2.0);
}
@Test
public void testFailedTransfer(){
//Подготовка
AccountInfoService mockInfoService = Mockito.mock(AccountInfoService.class);
Mockito.when(mockInfoService.getInfo(1)).thenReturn(new AccountInfo(1, 10.0));
Mockito.when(mockInfoService.getInfo(2)).thenThrow(RuntimeException.class);
TransferService transferService = new TransferService(mockInfoService, new TransferLogService());
...
}
@Test
public void testFailedTransfer(){
...
//Действия
transferService.makeTransfer(1,2, 2.0);
...
}
@Test
public void testFailedTransfer(){
...
//Проверки
Assert.assertEquals(1, transferService.getFailedTransfers());
}
@Test
public void testFailedTransfer(){
//Подготовка
AccountInfoService mockInfoService = Mockito.mock(AccountInfoService.class);
Mockito.when(mockInfoService.getInfo(1)).thenReturn(new AccountInfo(1, 10.0));
Mockito.when(mockInfoService.getInfo(2)).thenThrow(RuntimeException.class);
TransferService transferService = new TransferService(mockInfoService, new TransferLogService());
//Действия
transferService.makeTransfer(1,2, 2.0);
//Проверки
Assert.assertEquals(1, transferService.getFailedTransfers());
}
// Создаем новый webdriver с указанием geckodriver
System.setProperty("webdriver.gecko.driver", "${ путь до geckodriver }");
System.setProperty("webdriver.firefox.bin", "${ путь до firefox }");
WebDriver wd = new FirefoxDriver();
// Открываем гугл
wd.get("http://www.google.com");
final String searchString = "selenium";
// Находим поисковую строку и ищем "selenium"
WebElement searchBox = wd.findElement(By.name("q"));
searchBox.sendKeys(searchString);
searchBox.submit();
// т.к. google асинхронный - ждем поисковой выдачи
(new WebDriverWait(wd, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith(searchString);
}
});
// закрываем webdriver
wd.quit();
public class SeleniumTest
{
@Test
public void googleTest() throws Exception{
// Создаем новый webdriver с указанием geckodriver
System.setProperty("webdriver.gecko.driver", "${ путь до geckodriver }");
System.setProperty("webdriver.firefox.bin", "${ путь до firefox }");
WebDriver wd = new FirefoxDriver();
// Открываем гугл
wd.get("http://www.google.com");
final String searchString = "selenium";
// Находим поисковую строку и ищем "selenium"
WebElement searchBox = wd.findElement(By.name("q"));
searchBox.sendKeys(searchString);
searchBox.submit();
// т.к. google асинхронный - ждем поисковой выдачи
(new WebDriverWait(wd, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith(searchString);
}
});
// закрываем webdriver
wd.quit();
}
}
Тесты должны быть изолированны и не мешать друг другу
Измерить покрытие кода
Кол-во кода в % во время выполнения тестирования
org.jacoco
jacoco-maven-plugin
0.7.9
mvn clean install
Про модульное тестирование
Scenario: ищем в интернете Given: Я открываю www.google.com When: В поисковую строку я ввожу "java" Then: Я вижу в поисковой выдаче "java.com"
public class SearchSteps {
@Given("Я открываю (.*)")
public void openUrl(String url) { ... }
@When("В поисковую строку я ввожу (.*)")
public void search(String searchString) { ... }
@Then("Я вижу в поисковой выдаче (.*)")
public void searchResults(String expectedSearchResult) { ... }
}
*Проводить тестирование всегда стоит на одном и том же сервере
Умеет тестировать: