quinta-feira, 22 de setembro de 2016

Sobre encapsulamento

Antes de falarmos sobre o falso encapsulamento, primeiramente, o que é encapsulamento?

O encapsulamento serve para controlar o acesso aos atributos e métodos de uma classe, não permitindo o acesso direto aos dados.
Assim, pode-se determinar onde a classe poderá ser manipulada.
Modificadores de visibilidade fazem parte do encapsulamento.
Getters e Setters fazem parte do encapsulamento.

Encapsulamento também pode ser ligado a uma ideia de abstração,  separando os aspectos externos de um objeto, que são acessíveis a outros objetos, dos detalhes internos da implementação, que são escondidos de outros objetos.

Existe um equívoco cometido por alguns programadores ao pensar que ao criarem métodos getter e setter estão já dando por feito o trabalho do tal encapsulamento.

O fato de haver getters e setters não gera já o encapsulamento.
Se eu tenho um cenário em que: 
- coloco um atributo como privado
- mas tenho getter e setter público na qual o atributo pode ser obtido através do getter e modificado através do setter
Não está havendo um real encapsulamento e nada está funcionando diferente do que se o atributo estivesse como público e estivesse sendo acessado e alterado diretamente.


Para evitar retornar uma informação com o getter e ela ser alterada por outros de maneira indesejada, ao invés de retornar diretamente o objeto em questão pode-se:
- retornar apenas um clone dele
ou
- ter métodos para retornar apenas informação propriamente dita de atributos do objeto, não retornando o objeto por inteiro
Essas seriam maneiras de retornar apenas a informação desejada para quem a solicitou, sem entregar o objeto e correr o risco de que seus dados sejam alterados de modo indesejado.


Espero que as informações tenham sido úteis!
Até a próxima.

terça-feira, 9 de agosto de 2016

Query entre intervalos de datas no SQLServer

Quando vai ser feita uma query que busca um intervalo entre duas datas, se não for especificada hora, a query irá buscar apenas até o momento inicial do dia limite (até o momento 00:00:00.000) do dia, não buscando no dia completo. Qualquer resultado que seja após esse segundo inicial do dia limite não irá ser retornado na busca.
Para resolver isso, a busca por intervalos entre duas datas precisa ser feita:
- indicando também o intervalo de hora desejado
- incrementando o dia final, e ao invés de fazer between, colocar WHERE Date >= 'aaaa/mm/dd' and Date < 'aaaa/mm/dd' (OBS: o segundo não é menor ou igual. É apenas menor)

Eu já tive problemas com isso ao não obter nos resultados da query os valores que estavam ao longo do dia final do intervalo indicado na query. No meu caso, como eu realmente queria tudo que estava também no dia limite, independente da hora, eu optei pela segunda opção dentre as duas que descrevi.

quinta-feira, 21 de julho de 2016

Operações numéricas nas concatenações entre Strings e numeros

Em java, qual a diferença no que seria impresso em cada um dos seguintes exemplos:

1) System.out.println("são " + 20 + 20 + 6);

2) System.out.println("são " + (20 + 20 + 6) );

?

Sim, existe diferença. 
Ao começar a fazer a concatenação de uma string, a operação de concatenação é feita até o final. Se for concatenada uma string com um número, esse número deixará de ser visto como um valor numérico e passará a ser visto como String. Assim também se dará com qualquer número que apareça no restante daquela concateação. Assim, se existem núemros com os quais se deseja trabalhar realmente como sendo números, é preciso fazer tais operações antes de fazer uma concatenação desejada com alguma String. Pode-se utilizar de parênteses para definir essa precedência nas operações.

No primeiro exemplo, ao colocar "são"+20 , isso já geraria um início de concatenação, por estar colocando uma string na soma. Logo, a partir daí, ia ir concatenando tudo até o final.
A saída de 1) seria: 20206

No segundo caso, um parênteses é colocado mudando a precedência: a primeira coisa a ser lida é 20+20+6. Apenas números, então serão realmente somados. Depois, seguindo a precedência, vai ser feito o "são "+ 46. 
A saída de 2) seria:46

domingo, 10 de julho de 2016

JUnit #3

É importante nos testes abranger também as situações que precisam gerar exceções, para testar se as exceções que precisavam ser disparadas em determinado momento realmente serão.

No JUnit, como isso pode ser feito?



No JUnit isso pode ser feito colocando ao lado da anotação @Test um (expected=nomeDaException.class)

Fazendo isso, o teste será bem sucedido se em qualquer lugar dentro do método de caso de teste acontecer a exceção esperada.

Se eu preciso na verdade conferir se a exceção acontece até antes de uma linha em particular, posso colocar fail(); em alguma linha e o teste é considerado falho se a exceção não acontecer até antes daquele ponto. O teste será bem sucedido se a exceção citada em (expected=nomeDaException.class) ocorrer antes daquele ponto.


ex:

@Test (expected=nomeDaException.class)
public void exemploTesteJUnit(){

try{
obj.metodo(-1);
fail();

} catch (Exception e){
//bla bla bla
}

}


Se é esperado que a linha obj.metodo(-1) lance a exceção do tipo nomeDaException.class, caso essa exceção seja disparada por esta linha o método será considerado bem sucedido, devido ao (expected=nomeDaException.class) indicado ao lado da anotação @Test. 
Mas se chegar na linha onde está o método fail() e a exceção esperada não tiver ainda sido lançada, o teste terá falhado.

segunda-feira, 4 de julho de 2016

Sobre acoplamento

Acoplamento é um princípio muito importante na engenharia de software.
Acoplamento significa o quanto as classes são dependentes entre si para funcionar. Quanto maior a dependência entre as classes, maior o acoplamento.

Um alto acoplamento é algo indesejado para a arquitetura de um software, pois pode acarretar uma série de problemas de manutenção e gerenciamento, fazendo com que mudanças e evoluções feitas em determinada parte do código repercutam em diversos outros lugares. 

Para evitar chamadas desordenadas de mensagens entre objetos e consequente criação de dependências e acoplamento excessivos, podemos utilizar algumas regras para restringir essa chamada de mensagens entre objetos de modo a evitar muito acoplamento. O ideal seria que um método de um objeto faça invocações apenas dos seguintes tipos:

- pode-se chamar métodos dos objetos do tipos dos atributos da classe (não seria um problema porque a dependência com tais classes já está explicitada porque a classe já usa objetos dessas outras classes como atributos)

- pode chamar métodos dos objetos passados como parâmetro para o método (não seria um problema porque a dependência com as classes desses objetos já está explicitada por tais objetos serem pedidos como parâmetros para o método)

- pode a colaboração de outros métodos da mesma classe (ou seja, usando o this)

- pode chamar classes do próprio java (String, Calendar, etc)

Estar com essas regras em mente facilita a criação do código já com baixo acoplamento e evita que o trabalho de diminuição do acoplamento precise ser feito posteriormente quando o código talvez se mostrar problemático.


domingo, 26 de junho de 2016

JUnit #2

Continuando a falar sobre o JUnit, agora vamos ver algumas anotações que podem ser utilizadas para preparações antes de rodar os testes (como abertura de conexões, por exemplo) ou para ações a serem realizadas após o fim dos testes (como fechamento de conexões, por exemplo).


@Before deve ser usado como anotação acima do método que tenha o que deve ser executado antes de qualquer um dos casos de teste. Se forem rodados 5 testes, por exemplo, o método com @Before será executado 5 vezes, uma antes de cada um deles.

@After deve ser usado como anotação acima do método que tenha o que deve ser executado depois de qualquer um dos casos de teste. Se forem rodados 5 testes, por exemplo, o método com @After será executado 5 vezes, uma depois de cada um deles.

@BeforeClass deve ser usado como anotação acima do método que tenha o que deve ser executado uma única vez antes dos casos de teste da classe. Não importa quantos casos de testes haja, o método com @BeforeClass será executado apenas uma vez, antes que comecem os casos de teste.

@AfterClass deve ser usado como anotação acima do método que tenha o que deve ser executado uma única vez depois dos casos de teste da classe. Não importa quantos casos de testes haja, o método com @AfterClass será executado apenas uma vez, depois que terminarem todos os casos de teste da classe.

sábado, 25 de junho de 2016

JUnit #1

O JUnit é um framework java de código aberto para gerar testes unitários. Ele normalmente já possui seu ".jar" incluído na maioria das IDEs populares. Através dele, classes de teste podem ser criadas e nestas classes casos de teste podem construídos para testar de maneira automatizada as classes alvo.

Para cada método da classe-alvo que se desejar testar é criado um caso de teste.
Nesses casos de teste o desenvolvedor define quais serão os dados a serem utilizados como entrada no método a ser testado e qual o valor de saída esperado como consequência daquelas entradas. Faz-se a comparação se o resultado obtido realmente coincide com o que era esperado, considerando os parâmetros que foram passados ao método. Além disso, casos de teste também podem ser utilizados para verificar o lançamento ou não de exceções esperadas, entre outras situações.

JUnit possui diversos métodos "assert" para fazer a comparação entre os valores esperado e obtido. Um destes métodos é o assertEquals(valorEsperado, valorObtido), que retornará true e fará o teste passar caso os valores sejam iguais. Além do assertEquals também existem diversos outros como o AssertNull, assertTrue, assertSame, assertArrayEquals, etc. Confira em http://goo.gl/2Wvqbe.
É possível também implementar um próprio método assert.

Exemplo de um caso de teste, chamado exemploTesteJUnit:


import static org.junit.Assert.*;

import org.junit.Test;



public class principalTeste {

@Test
public void CalculadoraTest(){

    Calculadora calc = new Calculadora();
    int resultado = calc.soma(4,4);
    assertEquals(8,resultado);
}

}


Após criar os testes automatizados, basta, na opção exibida pela IDE, mandar que os testes sejam rodados e será apontado então em quais testes houve aprovação e reprovação.

Conforme o código das classes vai sendo alterado com o passar do tempo, funcionalidades que já funcionavam podem acabar deixando de funcionar e rodar os testes unitários automatizados já criados anteriormente permite conferir se os métodos avaliados pelos testes continuam fazendo o que deveriam fazer conforme haviam sido aprovados antes.

Na organização do projeto, normalmente cria-se um pacote em separado para colocar as classes de teste e para cada classe a ser testada, cria-se uma classe de teste.
Dentro de uma classe de teste, cria-se um método de teste para cada método da classe original que se pretende testar. Acima de cada método de teste (os chamados casos de teste) deve haver uma anotação @Test.

Segundo processos de desenvolvimento como TDD e XP, o ideal é criar os testes unitários antes de começar o desenvolvimento e posteriormente criar o código para que se possa ser aprovado em tais testes. Tenho começado a estudar sobre TDD ultimamente e, por mais que seja um pensamento diferente do que eu costumava utilizar no desenvolvimento e cause um estranhamento inicial, tem se mostrado um bom caminho para o desenvolvimento de software que pretendo começar a seguir. Posteriormente, em alguma outra postagem, falo melhor sobre o TDD.

Na postagem a seguir falarei sobre algumas outras anotações que podem ser utilizadas no JUnit e na outra depois desta falarei sobre o uso de casos de teste para verificar o lançamento de exceções.

Até a próxima.