• Nenhum resultado encontrado

Spring Framework. Parte 02 acesso a dados e testes de integração

N/A
N/A
Protected

Academic year: 2021

Share "Spring Framework. Parte 02 acesso a dados e testes de integração"

Copied!
47
0
0

Texto

(1)

Spring Framework

Parte 02 – acesso a dados e testes de

integração

(2)

H2 Database

• H2 é um SGBDR escrito em Java que pode atuar

tanto no modo embutido como na forma

cliente-servidor.

• Após instalação, executar o script h2.bat, ou

h2.sh, presente no diretório bin. Em seguida, usar

o navegador para acessar o endereço

http://192.168.56.1:8082/.

(3)

Dependências

<dependency>

<groupId>com.h2database</groupId>

<artifactId>h2</artifactId>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

</dependency>

(4)

Classes de configuração

• Classe AppConfig: configurações gerais da

aplicação que não possuem relação com a parte

web.

• Class AppConfigTest: configurações específicas

para execução de testes automatizados.

(5)

Classes de configuração: AppConfig

package cursoSpring.revenda_veiculos.config; import javax.sql.DataSource; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DriverManagerDataSource; @Configuration

public class AppConfig { @Bean

public DataSource dataSource(){

DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("org.h2.Driver"); ds.setUrl("jdbc:h2:tcp://localhost/~/curso_spring"); ds.setUsername("sa"); ds.setPassword(""); return ds; }

(6)

Classes de configuração: AppConfig

package cursoSpring.revenda_veiculos.config; import javax.sql.DataSource; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DriverManagerDataSource; @Configuration

public class AppConfig { @Bean

public DataSource dataSource(){

DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("org.h2.Driver"); ds.setUrl("jdbc:h2:tcp://localhost/~/curso_spring"); ds.setUsername("sa"); ds.setPassword(""); return ds; }

DriverManagerDataSource é uma implementação de DataSource que deve ser utilizada apenas em tempo

de desenvolvimento. Para produção, deve-se utilizar uma implementação que trabalhe com pool de conexões tal como Apache Commons DBCP ou C3P0.

(7)

Classes de configuração: AppConfigTest

package cursoSpring.revenda_veiculos.config;

import org.springframework.context.annotation.Profile; ...

@Configuration

public class AppConfigTest { @Bean

@Profile("test")

public DataSource dataSource(){

DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("org.h2.Driver"); ds.setUrl("jdbc:h2:tcp://localhost/~/curso_spring_test"); ds.setUsername("sa"); ds.setPassword(""); return ds; }

Crie esta classe na source folder

(8)

Entidade genérica

package cursoSpring.revenda_veiculos.dominio; import java.io.Serializable;

public abstract class Entidade implements Serializable{ private Integer id;

public Entidade() {}

public Entidade(Integer id) { super();

this.id = id; }

public Integer getId() { ... }

public void setId(Integer id) { .. } @Override public int hashCode() { ... }

@Override public boolean equals(Object obj) { ... } }

Use o assistente do Eclipse para criar os métodos getId,

(9)

Entidade Fabricante

package cursoSpring.revenda_veiculos.dominio; public class Fabricante extends Entidade{

private String descricao; public Fabricante() {}

public Fabricante(Integer id, String descricao) { super(id);

this.descricao = descricao; }

public String getDescricao() { ... }

public void setDescricao(String descricao) { ... } }

(10)

FabricanteRepository

package cursoSpring.revenda_veiculos.dominio; import java.util.List;

public interface FabricanteRepository { List<Fabricante> todos();

Fabricante getPorId(Integer idFabricante); Integer inserir(Fabricante f);

void atualizar(Fabricante f);

void excluir(Integer idFabricante); }

(11)

Spring JDBC

• Spring oferece classes que, se comparadas ao JDBC puro,

tornam mais simples o código de interação com banco de

dados. Além disso, provê uma hierarquia de exceções não

verificadas que facilitam o tratamento de exceções.

• Algumas classes:

– JdbcTemplate: facilita a manipulação de registros (select,

insert, update e delete).

– SimpleJdbcInsert: facilita a inserção de registros.

– BeanPropertyRowMapper: mapeamento pré-definido entre

atributos de um objeto e as colunas da tabela, facilitando as

operações de consulta.

– EmptyResultDataAccessException: exceção indicativa de que

uma consulta vazia, ou seja, sem registros.

(12)

Spring JDBC: hierarquia parcial de

exceções

(13)

FabricanteDAO (1)

package cursoSpring.revenda_veiculos.dao; ... import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Repository; import cursoSpring.revenda_veiculos.dominio.Fabricante; import cursoSpring.revenda_veiculos.dominio.FabricanteRepository; @Repository

public class FabricanteDAO implements FabricanteRepository { @Autowired

(14)

FabricanteDAO (1)

package cursoSpring.revenda_veiculos.dao; ... import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Repository; import cursoSpring.revenda_veiculos.dominio.Fabricante; import cursoSpring.revenda_veiculos.dominio.FabricanteRepository; @Repository

public class FabricanteDAO implements FabricanteRepository { @Autowired

private DataSource dataSource;

@Autowired indica uma injeção por

tipo. Assim, o contexto do Spring irá buscar um bean do tipo DataSource

para injetar neste atributo.

@Repository marca

FabricanteDAO como um bean

Spring da camada de persistência. Isto faz com que as exceções lançadas por FabricanteDAO sejam encapsuladas em exceções do tipo

DataAccessExcpetion, tornando as

(15)

FabricanteDAO (2)

@Override

public List<Fabricante> todos() {

String sql = "select * from FABRICANTES";

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); return jdbcTemplate.query(sql,

BeanPropertyRowMapper.newInstance(Fabricante.class)); }

(16)

FabricanteDAO (2)

@Override

public List<Fabricante> todos() {

String sql = "select * from FABRICANTES";

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); return jdbcTemplate.query(sql,

BeanPropertyRowMapper.newInstance(Fabricante.class)); }

O método query varre os registros obtidos na consulta e retorna uma lista parametrizada pelo RowMapper<T> utilizado como parâmetro. BeanPropertyRowMapper é uma implementação disponibilizada pelo Spring que casa o nome de um atributo (e.g,

numeroPlaca) com a coluna de mesmo nome (e.g., NUMEROPLACA

(17)

Consulta com JDBC puro

try{

Connection con = getConnection();

String sql = "select * from fabricantes";

PreparedStatement prep = con.prepareStatement(sql); ResultSet rs = prep.executeQuery();

List<Fabricante> fabricantes = new ArrayList<Fabricante>(); while(rs.next()){

Fabricante f = new Fabricante(); f.setId(rs.getInt("ID"); f.setDescricao(rs.getString("DESCRICAO")); fabricantes.add(f); } return fabricantes; }catch(SQLException ex){ ... }

(18)

FabricanteDAO (3)

@Override

public Fabricante getPorId(Integer idFabricante) {

String sql = "select * from FABRICANTES where ID = ?"; JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); try{ return jdbcTemplate.queryForObject(sql, BeanPropertyRowMapper.newInstance(Fabricante.class), idFabricante); }catch(EmptyResultDataAccessException ex){ return null; } }

(19)

FabricanteDAO (4)

@Override

public Integer inserir(Fabricante f) {

SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(dataSource) .withTableName("FABRICANTES")

.usingGeneratedKeyColumns("ID"); Map<String, Object> params = new HashMap<>();

params.put("DESCRICAO", f.getDescricao());

Integer id = jdbcInsert.executeAndReturnKey(params).intValue(); f.setId(id);

return id; }

(20)

FabricanteDAO (5)

@Override

public void atualizar(Fabricante f) {

String sql = "update FABRICANTES set DESCRICAO=? where ID=?"; JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

jdbcTemplate.update(sql, f.getDescricao(), f.getId()); }

@Override

public void excluir(Integer idFabricante) {

String sql = "delete from FABRICANTES where ID = ?";

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.update(sql, idFabricante);

} }

(21)

Atualizando AppConfig

• Adicionando o pacote

cursoSpring.revenda_veiculos.dao ao contexto

do Spring:

package cursoSpring.revenda_veiculos.config; ... @Configuration @ComponentScan(basePackageClasses={FabricanteDAO.class})

public class AppConfig { ...

(22)

Testes de integração

• Os testes de integração devem se comunicar com

o banco de dados. Para tal, é preciso que o código

de testes tenha acesso ao contexto do Spring.

• Spring oferece suporte aos frameworks JUnit e

TestNG.

• Vamos utilizar os recursos do Eclipse, ao invés do

Maven, para execução dos testes JUnit. Portanto,

devemos adicionara a biblioteca do JUnit 4

(23)

Testes de integração

• Para que uma classe de testes do JUnit tenha

acesso ao contexto do Spring, podemos marcá-la

com @RunWith(SpringJUnit4ClassRunner.class)

ou defini-la como subclasse de

AbstractTransactionalJUnit4SpringContextTests.

• A anotação @ActiveProfiles será utilizada para

indicar o profile utilizado nos testes. Dessa forma,

os testes de integração utilizarão o DataSource

(24)

Scripts SQL

• Criar os seguintes scripts em src/test/java:

create-schema.sql

create table FABRICANTES (ID int auto_increment, DESCRICAO varchar(40) unique not null, primary key(ID));

insert into FABRICANTES (ID, DESCRICAO) values (1, 'CHEVROLET/GM'); insert into FABRICANTES (ID, DESCRICAO) values (2, 'FIAT');

insert into FABRICANTES (ID, DESCRICAO) values (3, 'FORD');

insert into FABRICANTES (ID, DESCRICAO) values (4, 'VOLKSWAGEN'); insert into FABRICANTES (ID, DESCRICAO) values (5, 'RENAULT');

drop-schema.sql

(25)

FabricanteDAOTest (1)

package cursoSpring.revenda_veiculos.dao; ... import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4S pringContextTests; @ContextConfiguration(classes={AppConfig.class, AppConfigTest.class}) @ActiveProfiles("test")

public class FabricanteDAOTest extends

AbstractTransactionalJUnit4SpringContextTests{ @Autowired

(26)

FabricanteDAOTest (2)

@Before

public void setUp(){

executeSqlScript("classpath:/create-schema.sql", false); }

@After

public void tearDown(){

executeSqlScript("classpath:/drop-schema.sql", false); }

@Test

public void testTodos() {

List<Fabricante> lista = dao.todos(); Assert.assertEquals(5, lista.size()); }

(27)

FabricanteDAOTest (3)

@Test

public void testGetPorId_1(){

Fabricante f = dao.getPorId(1);

Assert.assertEquals(1, f.getId().intValue());

Assert.assertEquals("CHEVROLET/GM", f.getDescricao()); }

@Test

public void testGetPorId_2(){

Fabricante f = dao.getPorId(20); Assert.assertNull(f);

}

@Test

public void testInserir(){

Fabricante f = new Fabricante(null, "TESTE"); Integer id = dao.inserir(f);

(28)

FabricanteDAOTest (4)

@Test

public void testAtualizar(){ Integer idFabricante = 3;

String novaDescricao = "NISSAN";

Fabricante f = new Fabricante(idFabricante, novaDescricao); dao.atualizar(f);

String descricao = jdbcTemplate.queryForObject(

"select DESCRICAO from FABRICANTES where ID = ?", String.class, idFabricante);

Assert.assertEquals(novaDescricao, descricao); }

@Test

public void testExcluir(){ Integer idFabricante = 2; dao.excluir(idFabricante);

Fabricante f = dao.getPorId(idFabricante); Assert.assertNull(f);

(29)

DAO com Hibernate

• Adicionar as dependências.

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-entitymanager</artifactId>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-orm</artifactId>

</dependency>

(30)

Configurando Hibernate: AppConfig (1)

... import org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManageme nt; @Configuration @ComponentScan(basePackageClasses={FabricanteDAO.class}) @EnableTransactionManagement

public class AppConfig {

(31)

Configurando Hibernate: AppConfig (2)

... @Bean

public LocalSessionFactoryBean sessionFactory(){ LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); sessionFactory.setPackagesToScan ("cursoSpring.revenda_veiculos.dominio"); sessionFactory.setHibernateProperties(hibernateProperties()); return sessionFactory; }

(32)

Configurando Hibernate: AppConfig (3)

private Properties hibernateProperties(){ Properties props = new Properties(); props.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); props.put("hibernate.show_sql", "true"); props.put("hibernate.format_sql", "true"); return props; } @Bean

public PlatformTransactionManager transactionManager(){ return new HibernateTransactionManager(

sessionFactory().getObject()); }

(33)

Scripts SQL

• Adicionar instruções:

create-schema.sql

...

create table MODELOS (ID int auto_increment, DESCRICAO varchar(40) not null, ID_FABRICANTE int not null, primary key(ID), foreign key (ID_FABRICANTE) references FABRICANTES);

insert into MODELOS (ID, DESCRICAO, ID_FABRICANTE) values (1, 'CORSA', 1);

insert into MODELOS (ID, DESCRICAO, ID_FABRICANTE) values (2, 'GOL', 4);

insert into MODELOS (ID, DESCRICAO, ID_FABRICANTE) values (3, 'PALIO', 2);

drop-schema.sql

(34)

Atualizando classe Entidade

... import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; @MappedSuperclass

public abstract class Entidade implements Serializable{ @Id

@GeneratedValue(strategy=GenerationType.AUTO)

private Integer id; ...

(35)

Atualizando classe Fabricante

... import javax.persistence.Entity; import javax.persistence.Table; @Entity @Table(name="FABRICANTES")

public class Fabricante extends Entidade{ ...

(36)

Entidade Modelo (1)

package cursoSpring.revenda_veiculos.dominio; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="MODELOS")

public class Modelo extends Entidade { private String descricao;

@ManyToOne

@JoinColumn(name="ID_FABRICANTE") private Fabricante fabricante;

(37)

Entidade Modelo (2)

public Modelo() {}

public Modelo(Integer id, String descricao, Fabricante fabricante) {

super(id);

this.descricao = descricao; this.fabricante = fabricante; }

public String getDescricao() { ... }

public void setDescricao(String descricao) { ... } public Fabricante getFabricante() { ... }

public void setFabricante(Fabricante fabricante) { ... } }

(38)

Interface ModeloRepository

package cursoSpring.revenda_veiculos.dominio; import java.util.List;

public interface ModeloRepository { List<Modelo> todos();

Modelo getPorId(Integer idModelo); Integer inserir(Modelo m);

void atualizar(Modelo m);

void excluir(Integer idModelo); }

(39)

Classe ModeloDAO (1)

package cursoSpring.revenda_veiculos.dao; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import cursoSpring.revenda_veiculos.dominio.Modelo; import cursoSpring.revenda_veiculos.dominio.ModeloRepository; @Repository

public class ModeloDAO implements ModeloRepository { @Autowired

(40)

Classe ModeloDAO (2)

@Override

public List<Modelo> todos() {

Session session = sessionFactory.getCurrentSession(); return session.createQuery("from Modelo").list();

}

@Override

public Modelo getPorId(Integer idModelo) {

Session session = sessionFactory.getCurrentSession(); return (Modelo)session.get(Modelo.class, idModelo); }

@Override

public Integer inserir(Modelo m) {

sessionFactory.getCurrentSession().save(m); return m.getId();

(41)

Classe ModeloDAO (3)

@Override

public void atualizar(Modelo m) {

sessionFactory.getCurrentSession().merge(m); }

@Override

public void excluir(Integer idModelo) {

String hql = "delete Modelo where id = :idModelo"; Session session = sessionFactory.getCurrentSession(); Query q = session.createQuery(hql)

.setParameter("idModelo", idModelo); q.executeUpdate();

} }

(42)

Classe ModeloDAOTest (1)

package cursoSpring.revenda_veiculos.dao; ... @ContextConfiguration(classes={AppConfig.class, AppConfigTest.class}) @ActiveProfiles("test")

public class ModeloDAOTest extends

AbstractTransactionalJUnit4SpringContextTests{ @Autowired

private ModeloDAO dao; @Autowired

(43)

Classe ModeloDAOTest (2)

@Test

public void testTodos() {

List<Modelo> lista = dao.todos();

Assert.assertEquals(3, lista.size()); }

@Test

public void testGetPorId_1(){ Integer idModelo = 2; Modelo m = dao.getPorId(idModelo); Assert.assertEquals(idModelo, m.getId()); Assert.assertEquals("GOL", m.getDescricao()); } @Test

public void testGetPorId_2(){ Modelo m = dao.getPorId(20); Assert.assertNull(m);

(44)

Classe ModeloDAOTest (3)

@Test

public void testInserir(){

Fabricante f = new Fabricante(1, null); Modelo m = new Modelo(null, "TESTE", f); Integer id = dao.inserir(m);

Assert.assertNotNull(id); }

@Test

public void testAtualizar(){ Integer idModelo = 1;

String novaDescricao = "CELTA";

Fabricante f = new Fabricante(1, null);

Modelo m = new Modelo(idModelo, novaDescricao, f); dao.atualizar(m);

Modelo m2 = (Modelo)sessionFactory.getCurrentSession()

.get(Modelo.class, idModelo); Assert.assertEquals(novaDescricao, m2.getDescricao());

(45)

Classe ModeloDAOTest (4)

@Test

public void testExcluir(){ Integer idModelo = 3; dao.excluir(idModelo); Modelo m = dao.getPorId(idModelo); Assert.assertNull(m); } @Before

public void setUp(){

executeSqlScript("classpath:/create-schema.sql", false); }

@After

public void tearDown(){

executeSqlScript("classpath:/drop-schema.sql", false); }

(46)

Referências

• Deinum, Marten et al. Spring Recipes: a

problem-solution approach, 3ª ed. Apress, 2014.

• Johnson, Rod et al. Spring Framework Reference

Documentation, 4.2.1 release. Disponível em

<http://docs.spring.io/spring/docs/current/spring

-framework-reference/html/>

• Souza, Alberto. Spring MVC: domine o principal

framework web Java. São Paulo: Casa do Código,

2015.

(47)

Instituto Federal de Educação, Ciência e Tecnologia do Rio

Grande do Norte

Campus Natal Central

Diretoria Acadêmica de Gestão e Tecnologia da Informação

Curso de formação em Spring Framework 4

Parte 02 – acesso a dados e testes de integração

Autor: Alexandre Gomes de Lima

Referências

Documentos relacionados

É termo utilizado para descrever um método de ataque, onde alguém faz uso da persuasão, muitas vezes abusando da ingenuidade ou confiança do usuário, para obter informações que

Em pacientes que foram submetidos à cirurgia de revascularização (por exemplo: colocação de ponte de safena para substituir segmentos de artérias do coração entupidas) do

falar e tardios para irar-se, pois a ira do homem não produz a justiça de Deus. • Duas maneira de Deus exercer

O modal hidroviário tem grande participação na expansão da logística da soja mato-grossense para o arco norte, por meio da hidrovia Madeira, que não possui problemas de

Aqui na Principled Technologies, comparamos a experiência de conectar um sistema Dell Latitude Ultrabook com o novo processador Intel Core da 5ª geração a um monitor HD de

A Corte de Apelação de Colmar julgou com base na lei doméstica francesa, não na CISG, afirmando que ainda que o contrato de compra e venda apresente

No prazo de até trinta e seis meses, a contar da data da publicação deste Decreto, os serviços de transporte coletivo aéreo e os equipamentos de acesso às

A fim de evitar ou, quando tal não for praticável, reduzir as emissões para o solo e para a água provenientes do armazenamento de estrume sólido, a MTD consiste em utilizar