Anteprima
Vedrai una selezione di 6 pagine su 24
Advanced programming techniques Pag. 1 Advanced programming techniques Pag. 2
Anteprima di 6 pagg. su 24.
Scarica il documento per vederlo tutto.
Advanced programming techniques Pag. 6
Anteprima di 6 pagg. su 24.
Scarica il documento per vederlo tutto.
Advanced programming techniques Pag. 11
Anteprima di 6 pagg. su 24.
Scarica il documento per vederlo tutto.
Advanced programming techniques Pag. 16
Anteprima di 6 pagg. su 24.
Scarica il documento per vederlo tutto.
Advanced programming techniques Pag. 21
1 su 24
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

SNAPSHOT.Dependencies

In the pom.xml file, dependencies are specified in the <dependencies> section, each one within a <dependency> tag. The GAV (Group, Artifact, Version) and the scope (compile or test) are specified for each dependency. Maven handles recursive dependency systems, where a dependency you import has its own dependencies. The developer only needs to specify the direct dependencies called from the project code, and Maven handles the indirect dependencies. Cached dependencies are not downloaded again after the first time.

Maven also supports snapshot and code versions. Maven uses Java properties, defined as pairs of <key/value>, to define constants. For example:

<properties>
  <dbDriver>postgres</dbDriver>
</properties>

Then, that property can be referred to as ${dbDriver}.

Build with Maven:

  • Dependencies are downloaded.
  • The main code (in src/main/java) is compiled (only with the dependencies with scope compile).
  • The test code (in src/test/java) is compiled (with both dependencies scopes).
  • Tests are run.

and results are recorded;- jar with main code is created.

The Maven lifecycle is an ordered list of phases to follow, which have associated goals:

  • Maven plug-ins define goas that are attached to some phases;
  • some goals are bound to specific phases;
  • plug-in goals can be bound to specific phases in the pom.xml file.

The Maven lifecycle can be summarized with 3 steps: →

  1. clean: removes all the files from previous builds wipes away the target folder;
  2. default: generates all the artifacts of the current build and runs the tests;
  3. site: generates a website for the build with documentation and reports.

The default lifecycle is composed by some sub-phases:

  • validate: check whether the project is correct and all the necessary information is available;
  • compile: compile the source code of the project and creates .class files in target/classes;
  • test: test the compiled source code using a suitable unit testing framework (e.g. junit);
  • package: take the compiled code and package it in its

distributable format (jar);

verify: run any checks on results of the integration tests to ensure that the quality criteria are met;

install: install the package into the local repository;

deploy: done in build environment, copies the final package to the remote repository to share it with other devs.

From command line you can execute a phase by simply typing mvn <command>. By default maven executes the requested phase after having automatically executed all the previous ones.

Test goal: run with mvn test, it is composed by these steps:

  1. main Java sources are compiled into target/classes;
  2. main resources are copied into target/classes;
  3. test Java sources are compiled into target/test-classes;
  4. test resources are copied into target/test-classes;
  5. unit tests are executed.

By default maven executes all non-abstract classes that match: **/Test*.java, **/*Test.java, **/*Tests.java, **/*TestCase.java.

In maven the build (which is basically running mvn <command>) fails as soon as a goal

fails. For example, if a Java source file can't be compiled, or a test can't be compiled, or a unit test fails. Otherwise it succeeds.

You can specify maven to run a single goal within a specific phase by typing mvn phase:goal.

Every maven project has to specify one and only one specific packaging type, which identifies the main objective of the build of that project: the kind of generated artifacts (defaults to jar).

Maven can be used as a build tool from command line directly, but it's not convenient for development. Instead it's convenient to use an IDE like eclipse. In the end maven will be used on a continuous integration server.

Maven Reactor: mechanism to build multimodule project, it collects the modules to build from the <modules> section. Modules dependencies are respected since reactor compiles in dependency order and not in the specified order. Usually the parent pom is the one that contains the <modules> section but that's not a strict requirement.

Due to this non-strictness, sometimes it may be convenient to keep the parent and the aggregator POM (the one that simply lists all the modules of the project) separate. For a complex project, it may be useful to create different aggregator POMs for different purposes with different modules inclusion. <dependencyManagement> can be used to specify which dependency is only available to some specific modules. GroupId and artifactId specifications are required. So in the parent POM we put this tag, with a list of dependencies. In each POM then we just put the dependency with groupId/artifactId and maven automatically shares that dependency (without needing to specify the version) to that module. Plug-in configuration: A new plug-in can be configured within the <plugin> section: - specify the goal(s) to execute; - the specific phase in which the goals are executed. This happens inside the <executions> section that can contain several <execution> elements, each specifying the goal.

to run and the <configuration> for that execution.

If you specify a plug-in in the parent POM, it will be available also inside each module which is included in the <modules> section.

The goal package comes aftet the test and it gets executed only if the tests succeed. It generates 3 jars by default:

  • my-app.jar which contains the compiled version of the source code (the .class files);
  • my-app-sources.jar which contains the source code (the .java files);
  • my-app-javadoc.jar which contains the javadoc of the project.

<pluginManagement> can be used, just like dependencyManagement, to specify which module gets the configuration of a specific plug-in, instead of making it available and configured for all the modules. Those modules need to specify explicitly which plug-in they require by specifying the groupId and the artifactId of that plug-in.

For example, PIT (the framework for mutation testing) has a Maven plug-in, that can be configured in the <pluginManagement> section.

This way, the PIT plug-in is not executed on each standard build, but only on demand, since it actually takes some time to execute. For example, jacoco has a Maven plug-in as well, and it works like this. First it needs a goal called prepare-agent to be run before the tests, then jacoco executes code coverage after the tests and a report is created. The maven jacoco plug-in (as well as the others) can be configured in order to provide failure in case of not respected code quality. For example we can configure the jacoco plug-in to expect a code coverage of at least 99%, and if that is not the case the build fails. We can of course, just like when we were executing code coverage manually, exclude some classes or source files from the code coverage analysis. Maven profiles can be used to enable modules, plug-ins, dependencies and so on only in specific circumstances automatically. So, stuff defined within a profile tag is included in the build only if that profile is active. For example, since

jacoco slows down the execution by a lot (being at runtime), we can create a profile which includes the plug-in for jacoco only for specific builds, with the command line option -Pjacoco. Same can be done with PIT, since we don't want PIT on default builds. This way, we can configure the plug-ins that we need in the <pluginManagement> section and then create profiles for them inside the <profiles> tag.

Mocking Technique that allows to write tests for components that have dependencies. In general every class should focus on a single task only, and delegate everything else to other classes or external services, such as a database for example. If the real dependency is used (or the real database, or whatever) during a unit test, the principle of testing a unit in isolation is violated. During a unit test that uses a dependency, you have to assume that the dependencies of that SUT are implemented and tested correctly and do what they are supposed to do. The real dependency though is

used only during integration testing between already tested SUTs using mockups. This means that we don’t depend on external/internal dependencies when writing unit tests, because we create fake copies of the real dependency.

Don’t instantiate dependencies directly! Use them through abstractions (interfaces or abstract classes).

Stub: an answer from a dependency that is given to the method under test, useful only in that specific context.

An example of stubbing is: if a SUT uses a database method/query getAllElements() and we want to test the behavior of the SUT for a single element database, then we mock the database and the stub will be a getAllElements() that returns a list with only one element.

Testing the state means writing tests that verify:

  • the value returned by a method under test is as expected;
  • after calling a method the state of an object has changed as expected;
  • a combination of both.

During a test for a SUT that interacts with a collaborator (a dependency) we need to

test the interaction between the SUT and that specific collaborator. In particular the SUT will interact with the mock.

Manual mocking and stubbing is possible but it takes time. We need a tool: mockito.

To create a mock object simply import import static org.mockito.Mockito.*; and then use, e.g. for a database:

Database database = mock(Database.class);

mock takes as an argument an abstract class or an interface and creates on the fly a mock object of that class.

The process of stubbing is implemented through: when(method_is_called()).thenReturn(object_to_return);

For example in the database example we can:

when(database.getAllElements()).thenReturn(listOfElements);

Repository pattern: a way to implement the Data Access Layer (DAL) in a layered architecture. It implements the logic for accessing the database by providing methods to access and modify records.

There is another tool that is useful to verify that some specific methods are called. This is called spy and it’s used by invoking the spy

method upon creation of an object within a test.Employee employee = spy(new Employee("1", 1000));

Then that object is used within a verify method to check whether a specific method is called on that object with some specific parameters.

Mockito can also be used to verify exceptional cases, for example cases in which the application or a specific method should throw an exception when a certain condition is met. Mockito has some syntax to do that, and to force throwing an exception.

Non void methods: when(object.method()).thenThrow(new exception)

Void methods: doThrow(new exception).when(object).method()

GIT Version control system: keeps track of the history of a project in which each element of the history is a snapshot of that project. Everything is stored in a repository. If something goes wrong you can roll back to a specific snapshot to recover.

Dettagli
Publisher
A.A. 2021-2022
24 pagine
SSD Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher ElenaSmith di informazioni apprese con la frequenza delle lezioni di Advanced programming techniques e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Firenze o del prof Lorenzo Bettini.