JUnit в Spring MVC. Подключение и настройка JUnit в Spring MVC
Тестирование с помощью JUnit в Spring MVC. Подключение и настройка JUnit. Внедрение ресурсов и зависимостей в тестирующий класс
Обзор приложения Spring MVC + AngularJS + Bootstrap + HTML5
Используемые технологии и библиотеки
- Spring MVC 4.2.4.Release
- JUnit 4.12
- Maven 3.2.5
- IntelliJ IDEA 15.0.2
1. Описание задачи
Рассмотреть использование фреймворка JUnit в приложении Spring MVC. Создать тестовый класс с применением тестовых аннотаций. Произвести настройки в файле конфигурации Spring MVC.
2. Структура проекта
Для тестирования используются классы JDBCExampleTest и SampleTestBean. В них будут использованы классы из проекта: DBLog, SampleBean, User, JDBCExample.
3. pom.xml
Для использования фреймворка JUnit в Spring MVC необходимо подключить несколько зависимостей.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<!-- Spring --> <spring-framework.version>4.2.4.RELEASE</spring-framework.version> <!-- JUnit test --> <junit.version>4.12</junit.version> .... .... <!--JUnit Test--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- Test Artifacts with Spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <scope>test</scope> </dependency> |
Зависимость для JUnit позволяет использовать возможности этого фреймворка. Так же следует обратить внимание на подключенный модуль тестирования Spring. В рамках этой статьи рассказать об особенностях и возможностях этого модуля рассказать не получится (в документации на это выделено несколько глав). Модуль предоставляет широкий набор аннотаций (например здесь мы будем использовать @ContextConfiguration), возможности для тестирования ORM функционала (JDBCExampleTest в нашем приложении) и многое другое.
Полный конфиг pom.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.javastudy</groupId> <artifactId>mvc_html5_angular</artifactId> <version>1.0</version> <properties> <!-- Generic properties --> <java.version>1.8</java.version> <!-- Web --> <jsp.version>2.2</jsp.version> <!--Java standard tag library--> <jstl.version>1.2</jstl.version> <servlet.version>3.1.0</servlet.version> <!-- Spring --> <spring-framework.version>4.2.4.RELEASE</spring-framework.version> <!-- JUnit test --> <junit.version>4.12</junit.version> <!-- Logging --> <!--logback - improved version of log4j--> <logback.version>1.0.13</logback.version> <slf4j.version>1.7.13</slf4j.version> <!-- jackson json JSON Processing API --> <jackson.databind-version>2.2.3</jackson.databind-version> <!-- Hibernate / JPA --> <hibernate.version>5.0.1.Final</hibernate.version> <!-- I don't know why, but with 5.0.5 final app not working! --> <!-- Spring Data --> <spring-framework.data.version>1.9.1.RELEASE</spring-framework.data.version> <!-- Quartz scheduling framework --> <quartz.scheduling.version>2.2.1</quartz.scheduling.version> </properties> <dependencyManagement> <!--all spring dependencies --> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>${spring-framework.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!--bootstrap webjars.org--> <dependencies> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <!-- Other Servlet Web dependencies --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!--Servlet API--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>${jsp.version}</version> <scope>provided</scope> </dependency> <!-- Apache Commons File Upload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <!-- Excel view --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.12</version> </dependency> <!-- PDF view --> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.5</version> </dependency> <!-- HSQLDB embedded database. Встроенная база данных--> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.3.3</version> </dependency> <!-- Spring JDBC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <!--JUnit Test--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- Test Artifacts with Spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <scope>test</scope> </dependency> <!-- Logging with SLF4J & LogBack --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> <scope>runtime</scope> </dependency> <!--Contains org.springframework.mail.javamail--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring-framework.version}</version> </dependency> <!-- Spring MVC Mail Related Dependency --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <!-- Spring REST jackson JSON Processing API --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.databind-version}</version> </dependency> <!--Hibernate ORM--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <!--Hibernate validator (contains @NotEmpty)--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.1.0.Final</version> </dependency> <!--Spring Data--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>${spring-framework.data.version}</version> </dependency> <!-- Quartz scheduling framework --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.scheduling.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.8</source> <target>1.8</target> <compilerArgument>-Xlint:all</compilerArgument> <showWarnings>true</showWarnings> <showDeprecation>true</showDeprecation> </configuration> </plugin> </plugins> <!--need to find configs in tests in package web-inf like @ContextConfiguration(locations = {"classpath:/config/application-context.xml" --> <testResources> <testResource> <directory>src/main/webapp/WEB-INF/config</directory> </testResource> </testResources> </build> </project> |
4. Конфигурация Spring MVC
Для тех кто изучает материал последовательно стоит обратить внимание на закомментированный код из прошлых частей в конфигурации mvc-config.xml, который будет ронять приложение для этой части.
1 2 3 4 5 6 |
<!--Excel and PDF xml view configuration --> <!--disabling for jUnit test. --> <!--<bean class="org.springframework.web.servlet.view.XmlViewResolver">--> <!--<property name="order" value="0" />--> <!--<property name="location" value="/WEB-INF/config/excel-pdf-config.xml"/>--> <!--</bean>--> |
Каких-либо особенных настроек в приложение добавлять не нужно, поэтому размещу под катом настройки приложения Spring MVC.
mvc-config.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- context:component-scan This tag will scan @Component, @Repository, @Service, @Controller and also resolves @Autowired and @Qualifier --> <context:component-scan base-package="ru.javastudy.mvcHtml5Angular.mvc" /> <!-- mvc:annotation-driven configures Spring MVC annotations Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath. HttpMessageConverter support for @RequestBody method parameters and @ResponseBody method return values from @RequestMapping or @ExceptionHandler methods. --> <mvc:annotation-driven/> <!-- activate @Transactional JPA annotation --> <tx:annotation-driven/> <!-- ViewResolver bean config for mapping strings to jsp views --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- Example: a logical view name of 'showMessage' is mapped to '/WEB-INF/jsp/showMessage.jsp' --> <property name="order" value="1" /> <property name="prefix" value="/WEB-INF/view/" /> <property name="suffix" value=".jsp" /> </bean> <!-- File Upload bean config--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- set the maximum file size in bytes --> <property name="maxUploadSize" value="1000000"/> </bean> <!--Excel and PDF xml view configuration --> <!--disabling for jUnit test. --> <!--<bean class="org.springframework.web.servlet.view.XmlViewResolver">--> <!--<property name="order" value="0" />--> <!--<property name="location" value="/WEB-INF/config/excel-pdf-config.xml"/>--> <!--</bean>--> <mvc:view-controller path="/index.html" view-name="/index"/> <mvc:view-controller path="/about.html" view-name="/about/about"/> <mvc:view-controller path="/file.html" view-name="/file/file"/> <mvc:view-controller path="/jdbc.html" view-name="/jdbc/jdbc"/> <mvc:view-controller path="/email.html" view-name="/email/email"/> <mvc:view-controller path="/rest.html" view-name="/rest/rest"/> <mvc:view-controller path="/orm.html" view-name="/orm/orm"/> <mvc:view-controller path="/jstl.html" view-name="/jstl/jstl"/> <mvc:view-controller path="/scope.html" view-name="/scope/scope"/> <mvc:view-controller path="/cookie.html" view-name="/cookie/cookieView"/> <!-- Static Resources Configuration (get access to static sources such as CSS and JavaScript files) --> <mvc:resources mapping="/resources/**" location="/resources/" /> <!-- themes can be put in different folder such as <mvc:resources mapping="/resources/**" location="/resources/themeBlue" /> <mvc:resources mapping="/resources/**" location="/resources/themeGreen" /> --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/interceptorCall/*"/> <!--need to use ' /** ' not ' /* ' if you want to intercept all requests.--> <!--<mvc:mapping path="/**"/>--> <bean class="ru.javastudy.mvcHtml5Angular.mvc.interceptors.SiteInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans> |
application-context.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <!--find property file. See bean id='dataSource' for example ${jdbc.hsqldb.driverClass}--> <context:property-placeholder location="classpath:util.properties" /> <!-- XML Bean Definitions --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.hsqldb.driverClass}" /> <property name="url" value="${jdbc.hsqldb.url}" /> <property name="username" value="${jdbc.hsqldb.username}" /> <property name="password" value="${jdbc.hsqldb.password}" /> </bean> <!-- initialize Embedded DataSource. Встроенная база данных--> <jdbc:initialize-database data-source="dataSource"> <jdbc:script location="classpath:dbschema.sql"/> <jdbc:script location="classpath:test-data.sql"/> </jdbc:initialize-database> <!-- Java Mail Configuration --> <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="username" value="${java.mail.username}"/> <property name="password" value="${java.mail.password}"/> <property name="port" value="465"/> <property name="javaMailProperties"> <props> <prop key="mail.smtp.auth">true</prop> <prop key="mail.smtp.starttls.enable">true</prop> <prop key="mail.smtp.starttls.required">true</prop> <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop> <prop key="mail.smtp.host">${java.mail.host}</prop> </props> </property> </bean> <!-- Velocity Email Template Config Bean --> <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> <property name="resourceLoaderPath" value="/WEB-INF/email-templates/"/> </bean> <!-- REST template configuration --> <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/> <!--Do not forget activate @Transactional JPA annotation with <annotation-driven/>--> <!-- JPA Persistence Context and EntityManager configuration --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > <!--packagesToScan - search Entity and mapping them --> <property name="packagesToScan" value="ru.javastudy.mvcHtml5Angular.mvc.bean" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" > <property name="generateDdl" value="true" /> <property name="showSql" value="true" /> </bean> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">false</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- Automatic Transaction Participation--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!--not uses but could autowired in JDBCExample bean--> <!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> --> <!-- Quartz scheduling configuration --> <task:annotation-driven/> <!-- Quartz simple trigger --> <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="simpleQuartzJob" /> <property name="repeatInterval" value="1000" /> <property name="startDelay" value="1000" /> </bean> <!-- Quartz cron trigger --> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="quartzCronJob"/> <property name="cronExpression" value="0/30 * * * * ?" /> <!-- every 30 seconds (seconds, minutes, hours, day of month, month, day of week, year(optional)) --> </bean> <!-- Quartz job --> <bean id="simpleQuartzJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="simpleQuartzTask" /> <property name="targetMethod" value="simpleTaskMethod" /> </bean> <!-- Quartz cron job --> <bean id="quartzCronJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="cronQuartzTask" /> <property name="targetMethod" value="cronTaskMethod" /> </bean> <!-- Quartz simple task --> <bean id="simpleQuartzTask" class="ru.javastudy.mvcHtml5Angular.mvc.quartz.QuartzTask" /> <!-- Quartz cron task --> <bean id="cronQuartzTask" class="ru.javastudy.mvcHtml5Angular.mvc.quartz.CronQuartzTask" /> <!-- Quartz Scheduler --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="jobDetails"> <list> <ref bean="simpleQuartzJob" /> <ref bean="quartzCronJob" /> </list> </property> <property name="triggers"> <list> <ref bean="simpleTrigger" /> <ref bean="cronTrigger" /> </list> </property> </bean> <!-- ScheduleTask example. Use <context:component-scan base-package="ru.javastudy.mvcHtml5Angular.mvc.scheduling"/> and @Component on ru.javastudy.mvcHtml5Angular.mvc.scheduling.ScheduleTask or <bean id="scheduleTask" class="ru.javastudy.mvcHtml5Angular.mvc.scheduling.ScheduleTask"/> --> <!--End scheduling configuration --> </beans> |
5. Java классы
Приведу под катом Java классы, которые будут использоваться для тестирования. Если кому-то интересен смысловая нагрузка этих классов, то они были описаны в предыдущих частях (DBLog, JDBCExample, User — в части работы с JDBC). SampleBean — просто spring-бин c двумя полями, которые инициализируются при инициализации бина.
DBLog:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package ru.javastudy.mvcHtml5Angular.mvc.bean; import javax.xml.bind.annotation.XmlElement; import java.io.Serializable; /** * Created for JavaStudy.ru on 26.02.2016. */ public class DBLog implements Serializable { private static final long serialVersionUID = 1L; private int IDLOG; private String LOGSTRING; public DBLog() { } public DBLog (int idLog, String logString) { this.IDLOG = idLog; this.LOGSTRING = logString; } public int getIDLOG() { return IDLOG; } @XmlElement public void setIDLOG(int iDLOG) { IDLOG = iDLOG; } public String getLOGSTRING() { return LOGSTRING; } @XmlElement public void setLOGSTRING(String lOGSTRING) { LOGSTRING = lOGSTRING; } } |
SampleBean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package ru.javastudy.mvcHtml5Angular.mvc.bean; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /** * Created for JavaStudy.ru on 04.03.2016. */ @Component(value = "sampleBean") public class SampleBean { private String stringValue; private int number; public SampleBean() { } @PostConstruct public void init() { stringValue = "postConstructValue"; number = 666; } public String getStringValue() { return stringValue; } public void setStringValue(String stringValue) { this.stringValue = stringValue; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } } |
User:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
package ru.javastudy.mvcHtml5Angular.mvc.bean; import org.hibernate.validator.constraints.NotEmpty; import javax.persistence.*; import javax.validation.constraints.Size; /** * Created for JavaStudy.ru on 25.02.2016. */ @Entity @Table(name = "USER") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "IDUSER") private int idUser; @NotEmpty @Size(min = 5, max = 20) @Column(name = "USERNAME") private String username; @NotEmpty @Size(min=5, max=20) @Column(name="PASSWORD") private String password; @Column(name="ENABLED") private boolean enabled; public int getIdUser() { return idUser; } public void setIdUser(int idUser) { this.idUser = idUser; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } @Override public String toString() { return "User{" + "idUser=" + idUser + ", username='" + username + '\'' + ", password='" + password + '\'' + ", enabled=" + enabled + '}'; } } |
JDBCExample:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
package ru.javastudy.mvcHtml5Angular.mvc.jdbc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCreator; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; import ru.javastudy.mvcHtml5Angular.mvc.bean.DBLog; import ru.javastudy.mvcHtml5Angular.mvc.bean.User; import javax.annotation.PostConstruct; import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; /** * Created for JavaStudy.ru on 24.02.2016. */ @Repository public class JDBCExample { @Autowired DataSource dataSource; //look to application-context.xml bean id='dataSource' definition private JdbcTemplate jdbcTemplate; @PostConstruct public void init() { System.out.println("JDBCExample postConstruct is called. datasource = " + dataSource); jdbcTemplate = new JdbcTemplate(dataSource); } //JDBC TEMPLATE INSERT EXAMPLE public boolean insertLog(DBLog log) { System.out.println("JDBCExample: log(final String log) is called"); final String INSERT_SQL = "INSERT INTO LOG (LOGSTRING) VALUES (?)"; jdbcTemplate.update(new PreparedStatementCreator() { public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement(INSERT_SQL); preparedStatement.setString(1, log.getLOGSTRING()); return preparedStatement; } }); return true; } //JDBC TEMPLATE SELECT EXAMPLE public List<DBLog> queryAllLogs() { System.out.println("JDBCExample: queryAllLogs() is called"); final String QUERY_SQL = "SELECT * FROM LOG ORDER BY IDLOG"; List<DBLog> dbLogList = this.jdbcTemplate.query(QUERY_SQL, new RowMapper<DBLog>() { public DBLog mapRow(ResultSet resulSet, int rowNum) throws SQLException { System.out.println("Getting log: "+ rowNum + " content: " + resulSet.getString("LOGSTRING")); DBLog dbLog = new DBLog(); dbLog.setIDLOG(resulSet.getInt("IDLOG")); dbLog.setLOGSTRING(resulSet.getString("LOGSTRING")); return dbLog; } }); return dbLogList; } public List<User> queryAllUsers() { System.out.println("JDBCExample: queryAllUsers is called"); final String QUERY_SQL = "SELECT * FROM USER ORDER BY IDUSER"; List<User> userList = this.jdbcTemplate.query(QUERY_SQL, new RowMapper<User>() { public User mapRow(ResultSet resulSet, int rowNum) throws SQLException { User user = new User(); user.setIdUser(resulSet.getInt("IDUSER")); user.setUsername(resulSet.getString("USERNAME")); user.setPassword(resulSet.getString("PASSWORD")); user.setEnabled(resulSet.getBoolean("ENABLED")); return user; } }); return userList; } //JDBC TEMPLATE DELETE EXAMPLE public boolean deleteUSER(int iduser) { System.out.println("JDBCExample: deleteUSER called"); final String DELETE_SQL = "DELETE FROM USER WHERE IDUSER LIKE ?"; int result = jdbcTemplate.update(DELETE_SQL,new Object[]{iduser}); System.out.println("r" + result); if (result > 0) { System.out.println("User is deleted: " + iduser); return true; } else { return false; } } //JDBC TEMPLATE UPDATE EXAMPLE public boolean updateUserEnable(User u, boolean enable) { System.out.println("JDBCExample: updateUserEnable called"); final String UPDATE_SQL = "UPDATE USER SET ENABLED = ? WHERE USERNAME = ?"; int result = jdbcTemplate.update(UPDATE_SQL,new Object[]{enable, u.getUsername()}); if (result > 0) { System.out.println("User is updated: " + u.getUsername()); return true; } else { return false; } } } |
6. Классы для тестирования
Перейдем к классам по теме данной статьи. Рассмотрим как можно тестировать корректное создание бина в контексте Spring MVC, проверять какие-либо поля и переменные. Для этого был создан класс SampleTestBean.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package ru.javastudy.mvc.test.sample; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import ru.javastudy.mvcHtml5Angular.mvc.bean.SampleBean; /** * Created for JavaStudy.ru on 04.03.2016. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:mvc-config.xml", "classpath:application-context.xml"}) public class SampleTestBean { //Comment this 'bean class="org.springframework.web.servlet.view.XmlViewResolver" ' in mvc-context.xml //to avoid 'Caused by: java.lang.IllegalStateException:WebApplicationObjectSupport instance [org.springframework.web.servlet.view.XmlViewResolve' @Autowired private ApplicationContext applicationContext; @Test public void sampleTest() { SampleBean sampleBean = applicationContext.getBean("sampleBean", SampleBean.class); Assert.assertNotNull(sampleBean); sampleBean = (SampleBean) applicationContext.getBean("sampleBean"); Assert.assertNotNull(sampleBean); Assert.assertEquals(sampleBean.getNumber(), 666); Assert.assertEquals(sampleBean.getStringValue(), "postConstructValue"); } } |
Вначале мы используем две аннотации. @RunWith — аннотация из фреймворка JUnit. С помощью нее мы указываем как будем запускать наш тестирующий класс. Класс, который указывается для этой аннотации должен быть унаследован от Runner. В нашем случае мы указываем класс из пакета org.springframework.test.context.junit4, который был подключен в pom.xml в начале статьи.
Вторая важная аннотация — @ContextConfiguration. С помощью этой аннотации мы можем определить файлы конфигурации контекста Spring приложения. Здесь показана возможность перечисления нескольких xml файлов через запятую и в фигурных скобках. Далее внутри класса мы используем автосвязывание для получения доступа к объекту контекста приложения. С помощью него мы проверяем корректность создания бина, а также инициализацию двух полей этого бина.
6.1 Тестирование ORM класса в Spring MVC
Как было описано выше, в спринг предоставляет широкие возможности по тестированию функционала, связанного с работой с базами данных. Для примера был создан тестирующий класс JDBCExampleTest.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
package ru.javastudy.mvc.test.jdbc; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import ru.javastudy.mvcHtml5Angular.mvc.bean.DBLog; import ru.javastudy.mvcHtml5Angular.mvc.bean.User; import ru.javastudy.mvcHtml5Angular.mvc.jdbc.JDBCExample; import java.util.List; /** * Created for JavaStudy.ru on 24.02.2016. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:mvc-config.xml", "classpath:application-context.xml"}) public class JDBCExampleTest { //IMPORTANT - DISABLE THIS <bean class="org.springframework.web.servlet.view.XmlViewResolver"> in mvc-config.xml @Autowired private JDBCExample jdbcExample; //JDBC TEMPLATE INSERT TEST EXAMPLE @Test public void insertLogTest() { DBLog dbLog = new DBLog(10,"test Log 10"); Assert.assertTrue(jdbcExample.insertLog(dbLog)); } //JDBC TEMPLATE SELECT TEST EXAMPLE @Test public void queryAllLogsTest() { List<DBLog> dbLogs = jdbcExample.queryAllLogs(); Assert.assertNotNull(dbLogs); for (DBLog dbLog : jdbcExample.queryAllLogs()) { System.out.println("DBLog id: "+ dbLog.getIDLOG() + " DBLog logString: "+ dbLog.getLOGSTRING()); } } @Test public void queryAllUsers() { List<User> users = jdbcExample.queryAllUsers(); Assert.assertNotNull(users); for (User user : jdbcExample.queryAllUsers()) { System.out.println("User id: "+ user.getIdUser() + " User username: "+ user.getUsername()); } } //JDBC TEMPLATE DELETE TEST EXAMPLE @Test public void deleteUSERTest() { Assert.assertTrue(jdbcExample.deleteUSER(5)); } //JDBC TEMPLATE UPDATE TEST EXAMPLE @Test public void updateUserEnableTest() { User user = new User(); user.setUsername("test1@outlook.com"); Assert.assertTrue(jdbcExample.updateUserEnable(user, false)); } /*//TEST METHOD for Test Table inside HSQLDB @Test public void queryAllTestTableRecords() { List<Map<String, Object>> rows = jdbcTemplate.queryForList("SELECT * FROM TEST"); for (Map<String, Object> row : rows) { System.out.println("TESTTABLE tectcolumn: " + row.get("TESTCOLUMN")); } }*/ } |
Различные методы тестируют различные операции работы с базой данных (запись, удаление, получение данных).
7. Запуск тестирования
Если вы все делали последовательно, то среда разработки сама увидит тестирующие классы и предложит их запустить, но возможно вам придется в ручную указать пакеты, которые относятся к тестам.
Для запуска тестирования можно выбрать необходимый класс и нажать «плей».
После запуска увидим результаты прохождения тестов.
Вот примерно в такой последовательности можно объединить возможности модуля тестирования Spring и одного из самых популярных фреймворков для тестирования JUnit. Если вам необходимо серьезно покрыть тестами ваше приложение, то рекомендую ознакомиться с официальной документаций JUnit и Spring. Объем информации достаточно большой, но его изучение откроет широкие возможности для тестирования.
Исходные коды
MVC_AngularJS_Html5 full project — полный проект Spring MVC + AngularJS + Bootstrap + HTML5.
14. JUnit test — код для этой части