Unit testing is a software testing method by which individual units of source code […] are tested to determine whether they are fit for use.
https://en.wikipedia.org/wiki/Unit_testing
One can view a unit as the smallest testable part of an application. In OOP, a unit is often an entire interface, such as a class, but could be an individual method.
https://en.wikipedia.org/wiki/Unit_testing
public class Car {
public CarStatus start() {
Engine engine = new CarEngine();
if (engine.start()) {
return CarStatus.STARTED;
} else {
return CarStatus.NOT_STARTED;
}
}
}
public class Car {
private final Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public CarStatus start() {
if (engine.start()) {
return CarStatus.STARTED;
} else {
return CarStatus.NOT_STARTED;
}
}
}
IoC is a design principle in which custom-written portions of a computer program receive the flow of control from a generic framework.
Dependency injection is a technique whereby one object supplies the dependencies of another object.
-
Injection de ressources du serveur d’apps
-
Permet de préciser l’emplacement de la ressource
-
-
Injection sur le champ
@Stateless
public class MyComponent {
@Resource(lookup = "java:comp/env/jdbc/myDataSource")
private DataSource dataSource;
}
-
Injection de n’importe quel bean (ou EJB)
-
Injection par type
-
-
Injection via le champ ou le constructeur
Almost every concrete Java class that has a constructor with no parameters (or a constructor designated with the annotation @Inject) is a bean.
-
Activation via fichier
META-INF/beans.xml
-
Crée un bean pour chaque classe sur le classpath
Scope | Annotation |
---|---|
Requête |
|
Session |
|
Application |
|
public class Dependency {}
@WebServlet
public class MyServlet extends HttpServlet {
@Inject
private Dependency dependency;
}
Note
|
Aucune possibilité de test unitaire |
public class Dependency {}
@WebServlet
public class MyServlet extends HttpServlet {
@Inject
public MyServlet(Dependency dependency) {
// Do stuff
}
}
public interface Dependency {}
public class DependencyA implements Dependency {}
public class DependencyB implements Dependency {}
@WebServlet
public class MyServlet extends HttpServlet {
@Inject
public MyServlet(Dependency dependency) { }
}
javax.enterprise.inject.AmbiguousResolutionException: There is more than one Bean with type Dependency
public interface Dependency {}
@Named("A")
public class DependencyA implements Dependency {}
public class DependencyB implements Dependency {}
@WebServlet
public class MyServlet extends HttpServlet {
@Inject
public MyServlet(@Named("A") Dependency dep) { }
}
-
Manque de typage
-
Basé sur une chaîne de caractères
-
Possibilité de créer une annotation
-
Mais toujours une injection par nom
-
@Qualifier @Retention(RUNTIME) @Target({TYPE, PARAMETER})
public @interface ThisOne {}
public interface Dependency {}
@ThisOne
public class DependencyA implements Dependency {}
public class DependencyB implements Dependency {}
@WebServlet
public class MyServlet extends HttpServlet {
@Inject
public MyServlet(@ThisOne Dependency dep) { }
}
-
Exposer une classe externe (JDK ou librairie) en bean
-
Exposer un bean dont l’implémentation dépend du contexte
-
Exposer plusieurs beans avec la même implémentation
public interface TaxStrategy {}
public class SwissTaxStrategy implements TaxStrategy {}
public class FrenchTaxStrategy implements TaxStrategy {}
public class TaxStrategyFactory {
@Produces
public TaxStrategy getTaxStrategy() {
if ("ch".equals(Locale.getDefault().getCountry()) {
return new SwissTaxStrategy();
}
return new FrenchTaxStrategy();
}
}
public class TaxComputationServlet {
@Inject private TaxStrategy taxStrategy;
}
-
Gérer de la logique métier déterminée à l’exécution
-
Spécifier des beans pour un scénario de déploiement
-
Créer des beans utilisés uniquement pour les tests
Bean injecté | Exemple |
---|---|
Bean principal |
|
Bean configuré |
|
Possibilité d’exécuter du code :
-
Juste après l’instanciation
-
Juste avant la recollection par le ramasse-miettes
An interceptor is a class used to interpose in method invocations or lifecycle events that occur in an associated target class. The interceptor performs tasks, such as logging or auditing, that are separate from the business logic of the application and are repeated often within an application.
http://bit.ly/javaee-interceptor
-
Tracer l’exécution d’une méthode
-
Tracer le temps d’exécution d’une méthode
-
etc.
@InterceptorBinding
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
public @interface Logged { }
@Interceptor
@Logged
public class LoggingInterceptor {
@AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
long start = System.currentTimeMillis();
Object value = ctx.proceed();
System.out.println(
"[" + ctx.getMethod().getName() + "]: " +
(System.currentTimeMillis() - start) + " ms");
return value;
}
}
<beans>
<interceptors>
<class>
ch.frankel.LoggingInterceptor
</class>
</interceptors>
</beans>
Decorators are outwardly similar to interceptors. However, they actually perform tasks complementary to those performed by interceptors. […] Decorators, on the other hand, do perform business logic by intercepting business methods of beans.
http://bit.ly/javaee-decorator
-
Le décorateur doit implémenter la même interface que le bean décoré
-
Si plusieurs décorateurs s’appliquent, ils sont invoqués dans l’ordre du
beans.xml
public class Product implements HasPrice {
private final String name;
private final double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override public double getPrice() {
return price;
}
}
CDI implémente le pattern Observer
-
Injection du générateur d’évènements via CDI
-
Basé sur le type
Event<T>
-
-
Aucune restriction sur le type de l'Observer
-
Méthode configurée via
@Observe
-
-
Aucune restriction sur le type d’évènement
public class Subject {
private Event<String> event;
@Inject
public Subject(Event<String> event) {
this.event = event;
}
public sendTimestampEvent(String message) {
event.fire("[" + System.currentTimeMillis() + "]: "
+ message);
}
}
public class Observer {
public receiveEvent(@Observe String message) {
System.out.println("Received " + message);
}
}