blob: 575b5ac58a64a3a05dcbb04eda7773e393e4e5bd [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Использование встроенного контейнера EJB для тестирования приложений уровня предприятия
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Использование встроенного контейнера EJB для тестирования приложений уровня предприятия - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Использование встроенного контейнера EJB для тестирования приложений уровня предприятия
В этом учебном курсе демонстрируется создание и выполнение тестов JUnit для приложений Java EE уровня предприятия. В этом учебном курсе будет создано веб-приложение с классом сущности и сеансным компонентом. Сначала будет создан тестовый класс JUnit для сеансного компонента, потом тест будет выполнен во встроенном контейнере EJB. Затем к проекту будет добавлен класс сущности, а тестовый класс будет изменен, и к классу сущности будет добавлен тестовый метод.
*Упражнения по темам руководства*
* <<Exercise_1,Тестирование сеансного компонента>>
* <<Exercise_1a,Создание проекта>>
* <<Exercise_1b,Создание сеансового компонента>>
* <<Exercise_1c,Тестирование сеансного компонента>>
* <<Exercise_1d,Изменение теста для указания свойств контейнера>>
* <<Exercise_1e,Использование аннотаций @BeforeClass и @AfterClass>>
* <<Exercise_2,Тестирование класса сущности>>
* <<Exercise_2a,Создание класса сущностей>>
* <<Exercise_2b,Изменение сеансного компонента>>
* <<Exercise_2c,Тестирование класса сущности>>
* <<Exercise_3,Загрузка проекта решения>>
*Для работы с этим учебным курсом требуется следующее программное обеспечение и ресурсы.*
|===
|Программное обеспечение или материал |Требуемая версия
|link:/downloads/[+IDE NetBeans+] |7.2, 7.3, 7.4, 8.0, пакет Java EE
|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+Комплект для разработчика на языке Java (JDK)+] |версия 7 или 8
|GlassFish Server Open Source Edition 3.1.2.2 |3.1.x или 4.x
|===
*Примечания.*
* Для этого учебного курса требуется подключаемый модуль JUnit. Если подключаемый модуль JUnit не установлен, при установке среды IDE откройте диспетчер подключаемых модулей, выберите вкладку "Доступные подключаемые модули" и установите подключаемый модуль JUnit.
*Предпосылки*
Предполагается, что читатель обладает базовыми знаниями по следующим технологиям или опытом программирования с их использованием:
* Программирование на Java
* IDE NetBeans
Перед началом этого учебного курса рекомендуется ознакомиться со следующей документацией:
* link:javaee-gettingstarted.html[+Начало работы с приложениями Java EE+]
* link:../java/junit-intro.html[+Writing JUnit Tests in IDE NetBeans+]
* link:http://download.oracle.com/docs/cd/E19798-01/821-1754/gjlde/index.html[+Использование встраиваемого интерфейса API EJB 3.1 вместе со встроенным сервером GlassFish+]
Можно загрузить link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FWebAppJUnit.zip[+готовый проект в виде архива ZIP+].
== Тестирование сеансного компонента
В этом разделе будет создано простое веб-приложение Java EE, содержащее сеансный компонент и класс сущности.
=== Создание проекта
1. Выберите 'Файл' > 'Создать проект' (Ctrl-Shift-N; ⌘-Shift-N в Mac) в главном меню.
2. Выберите "Веб-приложение" в категории "Java Web". Нажмите кнопку "Далее".
3. Присвойте проекту имя *WebAppJUnit* и выберите его местоположение.
4. Снимите флажок "Использовать отдельную папку", если он установлен.
Нажмите кнопку "Далее".
. В качестве сервера выберите *GlassFish Server*, а в качестве версии Java EE - *Java EE 6 Web* или *Java EE 7 Web*.
Нажмите кнопку "Готово".
=== Создание компонента сеанса
В этом упражнении будет создан очень простой сеансный компонент, содержащий один метод для сложения двух чисел.
1. Щелкните правой кнопкой мыши проект WebAppJUnit в окне "Проекты" и выберите Создать > Другое.
2. Выберите "Сеансный компонент" в категории Enterprise JavaBeans. Нажмите кнопку "Далее".
3. В качестве имени EJB введите *MyBean*.
4. Для имени пакета введите *bean*.
5. Для "Тип сеанса" выберите "Без сохранения состояния". Нажмите кнопку 'Готово'.
При нажатии кнопки "Готово" в редакторе откроется новый класс.
. В редакторе добавьте к классу следующий метод ``addNumbers`` .
[source,java]
----
@Stateless
public class MyBean {
*public int addNumbers(int numberA, int numberB) {
return numberA + numberB;
}*
}
----
NOTE: Для выполнения заданий этого практического руководства не обязательно создавать аннотацию ``@LocalBean`` или реализацию интерфейса. Если представление не указано явным образом, по умолчанию компонент предоставляет безынтерфейсное представление.
. Сохраните изменения.
=== Тестирование сеансного компонента
В этом упражнении будет создан тестовый класс для сеансного компонента, который будет тестировать метод ``addNumbers`` . Среда IDE может создать новый тестовый класс и методы тестирования схемы на основе целевого класса.
1. В окне 'Проекты' щелкните класс ``MyBean`` правой кнопкой мыши и выберите Сервис > Создать тесты.
2. Выберите JUnit в списке 'Платформы'.
3. В диалоговом окне "Создать тесты" используйте значения по умолчанию. Нажмите кнопку "ОК".
image::images/create-tests-dialog.png[title="Диалоговое окно 'Создать тесты'"]
NOTE: При первом создании модульного теста JUnit необходимо указать версию JUnit. Выберите версию JUnit 4.x в диалоговом окне 'Выбор версии JUnit' и нажмите 'Выбрать'.
При нажатии кнопки "ОК" среда IDE создает файл ``MyBeanTest.java`` и открывает класс в редакторе.
В окне 'Проекты' видно, что среда IDE создала класс теста в узле 'Пакеты тестов'. По умолчанию среда IDE создает каркасный тестовый метод в тестовом классе, который вызывает ``javax.ejb.embeddable.EJBContainer.createEJBContainer()`` для создания экземпляра контейнера EJB. Метод ``createEJBContainer()`` это один из методов в классе link:http://download.oracle.com/javaee/6/api/javax/ejb/embeddable/EJBContainer.html[+ ``EJBContainer`` +], входящем в EJB 3.1 Embeddable API.
Если развернуть узел 'Библиотеки тестов' в окне 'Проекты', можно увидеть, что среда IDE автоматически добавила сервер GlassFish (встраиваемый контейнер) и JUnit 4.x как библиотеки тестов. Если развернуть библиотеку "Сервер GlassFish", можно увидеть, что библиотека содержит файл ``glassfish-embedded-static-shell.jar`` .
image::images/embedded-static-shell-jar.png[title="Структура проекта в окне 'Проекты'"]
NOTE: Файл JAR ``glassfish-embedded-static-shell.jar`` не содержит источников для встроенного контейнера EJB. Для файла ``glassfish-embedded-static-shell.jar`` требуется локальная установка GlassFish. Путь к классам для локальной установки GlassFish определяется целевым сервером для проекта. Целевой сервер можно изменить в диалоговом окне "Свойства" проекта.
. Измените созданный каркасный тестовый метод, чтобы указать значения для ``numberA`` , ``numberB`` и ``expResult`` и удалить вызов сбоя по умолчанию.
[source,java]
----
@Test
public void testAddNumbers() throws Exception {
System.out.println("addNumbers");
*int numberA = 1;
int numberB = 2;*
EJBContainer container = javax.ejb.embeddable.EJBContainer.createEJBContainer();
MyBean instance = (MyBean)container.getContext().lookup("java:global/classes/MyBean");
*int expResult = 3;*
int result = instance.addNumbers(numberA, numberB);
assertEquals(expResult, result);
container.close();
}
----
. Щелкните правой кнопкой мыши окно "Проекты" и выберите команду "Тест".
При выполнении теста в среде IDE откроется окно "Результаты тестирования", в котором отобразятся ход выполнения и результаты теста.
image::images/test-results1.png[title="Окно &quot;Результаты теста&quot;"]
Результаты будут сходны с данными в окне вывода.
[source,java]
----
Testsuite: bean.MyBeanTest
addNumbers
...
Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 31.272 sec
------------- Standard Output ---------------
addNumbers
...
------------- ---------------- ---------------
test-report:
test:
BUILD SUCCESSFUL (total time: 35 seconds)
----
=== Изменение теста для указания свойств контейнера
При использовании мастера создания тестов среда IDE создала каркасный тестовый класс по умолчанию, содержащий код для запуска контейнера EJB. В этом упражнении будет изменен созданный код для запуска контейнера, чтобы позволить указать дополнительные свойства для экземпляра встроенного контейнера.
1. Добавьте следующий код (выделен полужирным) к тестовому классу.
[source,java]
----
@Test
public void testAddNumbers() throws Exception {
System.out.println("addNumbers");
int numberA = 1;
int numberB = 2;
// Create a properties map to pass to the embeddable container:
*Map<String, Object> properties = new HashMap<String, Object>();*
// Use the MODULES property to specify the set of modules to be initialized,
// in this case a java.io.File
*properties.put(EJBContainer.MODULES, new File("build/jar"));*
// Create the container instance, passing it the properties map:
EJBContainer container = javax.ejb.embeddable.EJBContainer.createEJBContainer(*properties*);
// Create the instance using the container context to look up the bean
// in the directory that contains the built classes
MyBean instance = (MyBean) container.getContext().lookup("java:global/classes/MyBean");
int expResult = 3;
// Invoke the addNumbers method on the bean instance:
int result = instance.addNumbers(numberA, numberB);
assertEquals(expResult, result);
// Close the embeddable container:
container.close();
}
----
. Щелкните правой кнопкой мыши в редакторе и выберите команду 'Исправить операторы импорта' (Alt-Shift-I; ⌘-Shift-I в Mac) для добавления операторов импорта для ``java.util.HashMap`` и ``java.util.Map`` .
. Снова выполните тест для подтверждения работы измененного теста и правильности создания контейнера.
Можно нажать кнопку "Повторное выполнение" в окне "Результаты тестирования".
=== Использование аннотаций ``@BeforeClass`` и ``@AfterClass``
В этом упражнении будет изменен тестовый класс для создания отдельных методов для создания и отключения экземпляра контейнера. Это может быть полезным при необходимости выполнения нескольких тестов, которые могут использовать один экземпляр контейнера. При этом не требуется открывать и закрывать контейнер для каждого теста, вместо этого до запуска тестов создается один экземпляр, который закрывается после выполнения всех тестов.
В этом упражнении код создания контейнера EJB будет перемещен в метод ``setUpClass`` . Метод ``setUpClass`` аннотирован строкой ``@BeforeClass`` , используемой для обозначения метода, который будет выполнен первым до выполнения других методов в тестовом классе. В этом примере будет создан экземпляр контейнера до тестового метода ``testAddNumbers`` , контейнер будет существовать до его закрытия.
Аналогично код выключения контейнера будет перемещен в метод ``tearDownClass`` , аннотированный строкой ``@AfterClass`` .
1. Добавьте следующую строку к тестовому классу.
[source,java]
----
private static EJBContainer container;
----
. Скопируйте код создания контейнера из тестового метода ``testAddNumbers`` в метод ``setUpClass`` .
[source,java]
----
@BeforeClass
public static void setUpClass() *throws Exception* {
*Map<String, Object> properties = new HashMap<String, Object>();
properties.put(EJBContainer.MODULES, new File("build/jar"));
container = EJBContainer.createEJBContainer(properties);
System.out.println("Opening the container");*
}
----
. Скопируйте код закрытия контейнера из тестового метода ``testAddNumbers`` в метод ``tearDownClass`` .
[source,java]
----
@AfterClass
public static void tearDownClass() *throws Exception* {
*container.close();
System.out.println("Closing the container");*
}
----
. Удалите избыточный код из метода ``testAddNumbers`` . Сохраните изменения.
Теперь тестовый класс должен выглядеть следующим образом.
[source,java]
----
public class MyBeanTest {
private static EJBContainer container;
public MyBeanTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(EJBContainer.MODULES, new File("build/jar"));
container = EJBContainer.createEJBContainer(properties);
System.out.println("Opening the container");
}
@AfterClass
public static void tearDownClass() throws Exception {
container.close();
System.out.println("Closing the container");
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of addNumbers method, of class MyBean.
*/
@Test
public void testAddNumbers() throws Exception {
System.out.println("addNumbers");
int numberA = 1;
int numberB = 2;
// Create the instance using the container context to look up the bean
// in the directory that contains the built classes
MyBean instance = (MyBean) container.getContext().lookup("java:global/classes/MyBean");
int expResult = 3;
// Invoke the addNumbers method on the bean instance:
int result = instance.addNumbers(numberA, numberB);
assertEquals(expResult, result);
}
}
----
При повторном выполнении теста для подтверждения правильности создания и выключения контейнера можно увидеть вывод, сходный со следующим окном "Результаты тестирования.
image::images/test-results2a.png[title="Окно &quot;Результаты теста&quot;"]
Можно увидеть, что метод ``setUpClass`` выполнен до теста ``addNumbers`` и напечатал строку "Открытие контейнера".
== Тестирование класса сущности
В этом разделе будет создан класс сущности и блок сохранения состояния, а также изменен сеансный компонент для внедрения диспетчера сущностей и доступа к сущностям. Также к новому классу сущности будет добавлен простой метод для печати номера идентификатора записи в вывод. После этого к сеансному компоненту будет добавлено несколько простых методов для создания и проверки записей в базе данных.
=== Создание класса сущности
В этом разделе будет использоваться мастер создания класса сущности для создания класса сущности и блока сохранения состояния с настройками подключения к базе данных .
1. Щелкните правой кнопкой мыши проект WebAppJUnit в окне "Проекты" и выберите Создать > Другое.
2. Выберите класс сущности в категории сохранения состояния. Нажмите кнопку "Далее".
3. Введите *SimpleEntity* в качестве имени класса.
4. Выберите базовый элемент в раскрывающемся списке "Пакет".
5. Введите *int* как тип первичного ключа. Нажмите кнопку "Далее".
6. Используйте имя блока сохранения состояния и поставщика сохранения состояния по умолчанию.
7. Выберите ``jdbc/sample`` в качестве источника данных и "Удалить и создать" в качестве стратегии. Нажмите кнопку "Готово".
image::images/create-entity-wizard.png[title="Диалоговое окно создания классов сущностей"]
При нажатии кнопки "Готово" в редакторе откроется новый класс сущности. Если развернуть узел "Файлы настройки" в окне "Проекты, можно увидеть, что среда IDE автоматически создала файл ``persistence.xml`` , в котором определяются свойства единицы сохранения состояния ``WebAppJUnitPU`` .
. В редакторе добавьте к классу сущности следующее закрытое поле.
[source,java]
----
private String name;
----
. Щелкните правой кнопкой мыши в редакторе исходного кода, выберите пункт "Вставить код" (Alt-Insert; Ctrl-I на Mac) и выберите пункт "Методы получения и установки", чтобы открыть диалоговое окно "Создать методы получения и установки".
. В диалоговом окне выберите поле ``name`` . Нажмите кнопку 'Создать'.
. Добавьте к классу следующий метод.
[source,java]
----
public SimpleEntity(int id) {
this.id = id;
name = "Entity number " + id + " created at " + new Date();
}
----
. Аннотации ``@NamedQueries`` и ``@NamedQuery`` используются для создания именованного запроса SQL.
[source,java]
----
@Entity
*@NamedQueries({@NamedQuery(name = "SimpleEntity.findAll", query = "select e from SimpleEntity e")})*
public class SimpleEntity implements Serializable {
----
. Создание конструктора по умолчанию.
Можно щелкнуть значок предложения, отображающийся во внутреннем поле рядом с объявлением класса, чтобы среда IDE создала конструктор.
. Исправьте операторы импорта для добавления выражений импорта для ``javax.persistence.NamedQueries`` , ``javax.persistence.NamedQuery`` и ``java.util.Date`` . Сохраните изменения.
Помимо созданного кода по умолчанию теперь класс сущности должен выглядеть так, как показано ниже:
[source,java]
----
package bean;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
@Entity
@NamedQueries({@NamedQuery(name = "SimpleEntity.findAll", query = "select e from SimpleEntity e")})
public class SimpleEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
public SimpleEntity() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SimpleEntity(int id) {
this.id = id;
name = "Entity number " + id + " created at " + new Date();
}
...
}
----
=== Изменение сеансного компонента
В этом упражнении изменяется сеансный компонент ``MyBean`` для добавления методов для вставки и получения данных из таблицы базы данных.
1. Откройте файл ``MyBean.java`` в редакторе.
2. Щелкните редактор правой кнопкой мыши и выберите "Вставка кода" (Alt-Insert; Ctrl-I в Mac), затем выберите "Использовать диспетчер сущностей" во всплывающем меню.
При выборе "Использовать диспетчер сущностей" среда IDE добавляет к классу следующий код для вставки в диспетчер сущностей. Можно заметить, что имя блока сохранения состояния создается автоматически.
[source,java]
----
@PersistenceContext(unitName="WebAppJUnitPU")
private EntityManager em;
----
. Добавьте следующие методы ``verify`` и ``insert`` .
[source,java]
----
@PermitAll
public int verify() {
String result = null;
Query q = em.createNamedQuery("SimpleEntity.findAll");
Collection entities = q.getResultList();
int s = entities.size();
for (Object o : entities) {
SimpleEntity se = (SimpleEntity)o;
System.out.println("Found: " + se.getName());
}
return s;
}
@PermitAll
public void insert(int num) {
for (int i = 1; i <= num; i++) {
System.out.println("Inserting # " + i);
SimpleEntity e = new SimpleEntity(i);
em.persist(e);
}
}
----
. Исправьте операторы импорта, чтобы импортировать ``javax.persistence.Query`` , и сохраните изменения.
=== Тестирование класса сущности
В этом упражнении будет изменяться тестовый класс для добавления метода для тестирования возможности поиска приложением EJB и правильности поведения методов ``insert`` и ``verify`` .
1. Запустите базу данных JavaDB.
2. Откройте тестовый класс ``MyBeanTest.java`` в редакторе.
3. К тестовому классу добавьте следующий тестовый метод ``testInsert`` .
[source,java]
----
@Test
public void testInsert() throws Exception {
// Lookup the EJB
System.out.println("Looking up EJB...");
MyBean instance = (MyBean) container.getContext().lookup("java:global/classes/MyBean");
System.out.println("Inserting entities...");
instance.insert(5);
int res = instance.verify();
System.out.println("JPA call returned: " + res);
System.out.println("Done calling EJB");
Assert.assertTrue("Unexpected number of entities", (res == 5));
System.out.println("..........SUCCESSFULLY finished embedded test");
}
----
. Правой кнопкой мыши щелкните узел свойств в окне "Проекты" и выберите "Тест" во всплывающем меню.
Откройте окно "Результаты тестирования", в котором будет отображен вывод, сходный со следующим.
image::images/test-results2b.png[title="Окно результатов теста после добавления теста testInsert"]
Сообщения печати, добавленные к тестовому классу, позволяют проследить ход выполнения тестов и порядок их запуска.
Теперь, когда имеется тест для сеансного компонента, и известно, что класс сущности работает, можно приступить к созданию веб-интерфейса для приложения.
== Загрузка проекта решения
Решение для данного учебного курса в виде проекта можно загрузить несколькими способами.
* Загрузите link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FWebAppJUnit.zip[+архив завершенного проекта в формате zip+].
* Выполните проверку исходных файлов проекта на выходе из примеров NetBeans, выполнив перечисленные ниже действия.
1. Выберите в главном меню "Группа > Subversion > Проверить".
2. В диалоговом окне "Проверка" введите следующий URL-адрес репозитория:
``https://svn.netbeans.org/svn/samples~samples-source-code``
Нажмите кнопку "Далее".
. Нажмите кнопку Browse ("Обзор") для открытия диалогового окна Browse Repository Folders ("Обзор папок репозитория").
. Разверните корневой узел и выберите *samples/javaee/WebAppJUnit*. Нажмите кнопку "ОК".
. Укажите локальную папку для исходных файлов (папка должна быть пустой).
. Нажмите кнопку 'Готово'.
После нажатия кнопки "Готово" среда IDE инициализирует локальную папку в качестве репозитория Subversion и выполняет проверку исходных файлов проекта на выходе.
. Щелкните команду "Открыть проект" в диалоговом окне, которое появится после завершения проверки.
*Примечания.*
* Для получения исходных файлов на редактирование требуется клиент Subversion. For more about installing Subversion, see the section on link:../ide/subversion.html#settingUp[+Setting up Subversion+] in the link:../ide/subversion.html[+Guide to Subversion in IDE NetBeans+].
link:/about/contact_form.html?to=3&subject=Feedback:%20Using%20the%20Embedded%20EJB%20Container[+Отправить отзыв по этому учебному курсу+]
== Дополнительные сведения
For more information about using IDE NetBeans to develop Java EE applications, see the following resources:
* link:javaee-intro.html[+Введение в технологию Java EE +]
* link:javaee-gettingstarted.html[+Начало работы с приложениями Java EE+]
* link:../web/quickstart-webapps.html[+Введение в разработку веб-приложений+]
* link:../../trails/java-ee.html[+Учебная карта по Java EE и Java Web+]
Дополнительные сведения по использованию компонентов уровня предприятия EJB 3.1 см. в link:http://download.oracle.com/javaee/6/tutorial/doc/[+руководстве по Java EE 6+].
To send comments and suggestions, get support, and keep informed on the latest developments on the IDE NetBeans Java EE development features, link:../../../community/lists/top.html[+join the nbj2ee mailing list+].