В этой статье я покажу элементарный пример работы с Apex кодом, который будет включать такие этапы разработки как: создание объектов, написание триггеров, написание тестов и расскажу об их необходимости.
1. Вступление
2. Создание объекта и полей
3. Создание вспомогательного класса
4. Создание триггера
5. Написание юнит тестов
6. Deploy
Вступление
В этой статье я проведу вас через несколько этапов разработки. В первую очередь нужно будет создать объект Book и поле Price на этом объекте. После мы напишем вспомогательный класс где зададим логику добавления скидки на цену книги. Создадим триггер и используем в нём этот класс. Напишем тесты к нашему классу и триггеру, и затем я скажу немного о деплое кода.
Создание объекта и полей
И так, начнём.
-
Нажав на шестерёнку переходим на странице Setup на вашей dev org.
-
Переходим в Object manager | Create | Custom object
-
Указываем
Label : Book
Plural label : Books
Дальше жмём Save. -
Оказавшись на странице нашего объекта Book, переходим в Field & Relationships, и создаём новое поле.
-
Выбираем тип Number
-
Указываем
Field label : Price
Length : 10
Decimal Places : 2
Потом жмём Next | Next | Finish.
Создание вспомогательного класса
Если вы уже создали объект Book и поле Price, тогда продолжим, создав вспомогательный класс с простенькой логикой для вычисления скидки на книгу.
В вашем рабочем окружении создаём класс BookPriceController и добавляем в него метод :
public with sharing class BookPriceController {
public static void applyDiscount(List<Book__c> books) {
for(Book__c b : books) {
b.Price__c *= 0.9;
}
}
}
Давайте более детально рассмотрим метод.
Мы проходим в цикле по листу объектов типа Book__c, заметили что после имени объекта который мы создали добавилось __с , это является обозначением того что объект custom , т.е мы сами его создали. И при работе с Apex каждый используемый кастомный тип должен иметь такое окончание, за исключением SOQL запросов, там иногда требуется другое окончание, но об этом позже.
В цикле для каждой записи типа Book__c мы пересчитываем цену и тут же переписываем её, я думаю что вам уже знаком подобный код из Java или С#.
Создание триггера
- Создаём триггер(Apex Trigger). Называем его BookTrigger, указываем что триггер для объекта Book__c, во входных параметрах указываем Before Insert для того что бы перед тем как вставить нашу запись в базу данных salesforce мы могли обработать её в триггере.
trigger BookTrigger on Book__c (before insert) {
}
- Добавляем внутри триггера логику обработки:
-
List<Book__c> books = Trigger.new;
- позволяет нам получить все записи типа Book__c и временно сохранить их в массив books. Да, я сказал массив, потому что в Apex, List = Array.
Т.е List<Book__c> аналогично Book__c[ ]. -
BookPriceController.applyDiscount(books);
- добавляем вызов нашего вспомогательного класса и передаем в него полученный массив книг.
trigger BookTrigger on Book__c (before insert) {
List<Book__c> books = Trigger.new;
BookPriceController.applyDiscount(books);
}
Написание юнит тестов
- Далее следует написание тестов для нашего вспомогательного класса и триггера. Однако нам достаточно написать тесты для BookTrigger, и он автоматически покроет класс BookPriceController.
Создадим Unit Test Class, и назовём его BookPriceControllerTest. Если вы работаете через Intellij IDEA, то создавать нужно Unit Test Class.
@IsTest
private class BookPriceControllerTest {
}
Аннотация @IsTest
указывает на то что класс тестовый.
- Теперь нам нужны данные на которых мы могли оттестировать работу нашего триггера, но тестировать на текущих данных нашей организации очень нежелательно, и вообще никогда так не делайте!!! Для этого у нас есть возможность создать временные данные, которые будут создаваться в базе данных SF перед каждым тестом и после удаляться. И данные на нашей организации не “пострадают”.
Добавим метод :
@TestSetup
private static void setup() {
Book__c book = new Book__c(Name = 'Behind the Cloud', Price__c = 100);
insert book;
}
Рассмотри код детальнее.
@TestSetup
- указывает на то что метод будет создавать данные для тестирования, что бы не пришлось менять актуальные данные в своей организации.
Book__c book = new Book__c(Name = 'Behind the Cloud', Price__c = 100);
- это описание нашего объекта для тестирования, пока его ещё нет в нашей базе данных.
insert book
- вставляет новую запись в базу данных.
- Теперь у нас есть данные с которыми мы можем работать. Потому что как я сказал ранее, метод с аннотацией
@TestStup
будет выполняться перед каждым тестовым методом.Выполняются они кстати хаотично.
Добавим тестовым метод:
@IsTest
static void testBehavior() {
Book__c book = [
SELECT Price__c
FROM Book__c
WHERE Name = 'Behind the Cloud'
];
System.assertEquals(90, book.Price__c);
}
Рассмотри код детальнее.
@IsTest
- указывает на то что это тестовый метод.
Book__c book = [
SELECT Price__c
FROM Book__c
WHERE Name = 'Behind the Cloud'
];
Это SOQL запрос запрашивает книгу которую мы вставили в базу данных.
System.assertEquals(90, book.Price__c);
- проверка данных на валидность, мы знаем что цена должна была уменьшиться с 100 до 90, что мы собственно и проверяем.
- Осталось запустить этот тестовый класс и получить результаты выполнения всех тестовых методов в этом классе. После вы сможете увидеть на сколько процентов покрыт ваш код.
Где же мы тестируем триггер? Всё просто, при каждой вставке в БД, которую индицирует наш метод с аннотацией @TestSetup, ведь в нём есть insert DML операция. Т.е при каждой попытке вставить запись book в БД триггер срабатывает(параметр before insert способствует этому), и меняет значение Price.
Deploy
Написание юнит тестов необходимо, не только потому что это неотъемлемая часть разработки в большинстве языков и Apex не исключение, но и потому что для деплоя кода на production необходимо что бы хотя бы 75% кода были покрыты тестами и 100% из них проходили. Более детально про деплой кода можно почитать в статье : Deploy метаданных на организацию.