Skip to content
Snippets Groups Projects
Unverified Commit c3303795 authored by Thomas Clavier's avatar Thomas Clavier
Browse files

avant le cours

parent ffd24f73
Branches
No related tags found
No related merge requests found
---
author: Thomas Clavier
title: Il est beau mon test
---
# Programme parfait ?
C'est quoi un programme parfait ?
# Selon XP
* DRY (Don't Repeat Yourself)
* Simple
* Du code lisible
* Tous les tests passent
# DRY
Une information dupliquée c'est le meilleur moyen pour avoir une désynchronisation plus tard.
## Information dupliquée ?
Pour vous, dans quels cas a-t-on une information dupliquée ?
. . .
* Copier / Coller
* Fichier de configuration / Code
## Resource vs Java
```java
FileReader readerUtilisateur = new FileReader( getClass()
.getClassLoader()
.getResource("utilisateurs.json").getFile() );
List<Utilisateur> utilisateurs = JsonbBuilder.create()
.fromJson(readerUtilisateur);
UtilisateurDao utilisateurDao = BDDFactory.buildDao(UtilisateurDao.class);
if (! tableExist("utilisateurs") {
utilisateurDao.createTable();
for ( Utilisateur utilisateur: utilisateurs) {
utilisateurDao.insert(utilisateur);
}
}
```
```json
[
{"id": "1", "role": "admin", "nomPrenom": "Juliette", "motDePasse": "1234"},
{"id": "2", "role": "presta", "nomPrenom": "Toto", "motDePasse": "1234"},
{"id": "3", "role": "client", "nomPrenom": "Richard", "motDePasse": "1234"}
]
```
## Resource vs Java
```java
UtilisateurDao utilisateurDao = BDDFactory.buildDao(UtilisateurDao.class);
if (! tableExist("utilisateurs") {
utilisateurDao.createTable();
utilisateurDao.insert(new Utilisateur(ADMIN, "Juliette", "1234"));
utilisateurDao.insert(new Utilisateur(PRESTA, "Toto", "1234"));
utilisateurDao.insert(new Utilisateur(CLIENT, "Richard", "1234"));
}
```
## Complexité accidentelle
C'est la complexité introduite dans des programmes informatiques non en raison de la complexité du problème, mais de manière accidentelle en raison des choix de développement.
* Fichier de configuration vs code : oui si vos utilisateurs ne savent/peuvent pas éditer le code
* Fichier de données vs code : oui si c'est plus facile à mettre à jour (masse, données venant d'un autre système, etc.)
# Simple
* KISS (Keep It Simple Stupide)
* YAGNI (You Aren't Gona Need It)
## KISS <small>Simplicité technique</small>
```java
public static double average(List<Double> numbers) {
Double sum = 0.0;
for (Double number : numbers) {
sum += number;
}
if (numbers.size() > 0)
return sum / numbers.size();
return 0.0;
}
```
```java
public static double average(List<Double> numbers) {
return numbers.stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0);
}
```
## SOLID
* *S*ingle responsability
* *O*pen/closed
* *L*iskov substitution
* *I*nterface segregation
* *D*ependency inversion
## Loi de Demeter
```java
public class Ocean {
private final Cell[][] internalRepresentation;
public Cell[][] getInternalRepresentation() {
return internalRepresentation;
}
}
```
```java
Ocean pacific = new Ocean(3,3);
pacific.getInternalRepresentation()[0][0] = new Cell(Fish);
```
. . .
vs
```java
public class Ocean {
public Ocean putCellContentAt(CellContent content, int line, int col) {
internalRepresentation[line, col] = new Cell(content);
return this;
}
}
```
```java
Ocean pacific = Ocean.of(3,3).putCellContentAt(Fish,0,0);
```
## YAGNI <small>Simplicité fonctionnelle</small>
Et si un jour il faut configurer une semaine avec plus que 7 jours ?
```json
[
{"id": "1", "name": "lundi"},
{"id": "2", "name": "mardi"},
{"id": "3", "name": "mercredi"},
{"id": "4", "name": "jeudi"},
{"id": "5", "name": "vendredi"},
{"id": "6", "name": "samedi"},
{"id": "7", "name": "dimanche"},
]
```
. . .
C'est arrivé 1 fois depuis la création du calendrier grégorien en 525 ! Même si la semaine de 7 jours existe depuis Babylone en -1595.
# Lisible
C'est quoi un code lisible ?
## Lisible ?
```java
public void init() {
// Paramétrage
Properties properties = new Properties();
properties.setProperty("foreign_keys", "true");
// Connection à la base de données
Jdbi jdbi = Jdbi.create(basePath + "data.db", properties)
.installPlugin(new SQLitePlugin())
.installPlugin(new SqlObjectPlugin())
.registerArgument(new UUIDArgumentFactory());
// Initialisation avec un admin
if (!tableExist("users")) {
UserDao userDao = jdbi.onDemand(UserDao.class);
userDao.createUsersTable();
userDao.insert(new User("Admin", "AdminPassword"));
}
}
```
## No comment
```java
public void init() {
Jdbi jdbi = getDatabaseConnection();
initializeUsersTableWithDefaultAdmin(jdbi);
}
```
## No comment
```java
public void init() {
Properties properties = new Properties();
properties.setProperty("foreign_keys", "true");
Jdbi jdbi = Jdbi.create(basePath + "data.db", properties)
.installPlugin(new SQLitePlugin())
.installPlugin(new SqlObjectPlugin())
.registerArgument(new UUIDArgumentFactory());
if (!tableExist("users")) {
UserDao userDao = jdbi.onDemand(UserDao.class);
userDao.createUsersTable();
userDao.insert(new User("Admin", "AdminPassword"));
}
}
```
## Mémoire de travail
## Mémoire de travail
![](../includes/2pts.png)
## Mémoire de travail
![](../includes/6pts.png)
## Mémoire de travail
![](../includes/10pts.png)
## Mémoire de travail
![](../includes/20pts.png){height=400px}
. . .
* 2 informations : 4 groupes de 5
* et 1 opération : 4 × 5 = 20
## Mémoire de travail
* 7 +/- 2 éléments (instructions et/ou informations)
* L'entrainement permet de s'approprier des motifs
cf. travaux de Nelson Cowan, Alan Baddeley, Graham Hitch et neurosciences
. . .
```python
print([x for x in ["apple", "banana", "cherry", "kiwi", "mango"] if "a" in x])
```
## Indirection Implicite
```java
@Before
public void setEnvUp() { utilisateurdao.createTable(); }
@After
public void tearEnvDown() throws Exception { utilisateurdao.dropTable(); }
...
@Test
public void testCreateUtilisateur() {
Utilisateur utilisateur = sampleUtilisateur();
Response response = target("/utilisateurs").request()
.post(Entity.json(utilisateur));
Utilisateur entityFromDB = utilisateurdao.load(utilisateur.getName())
assertEquals(entityFromDB, utilisateur);
}
```
## Indirection Implicite
```java
@Test
public void testCreateUtilisateur() {
resetTableUtilisateur();
Utilisateur utilisateur = sampleUtilisateur();
Response response = target("/utilisateurs").request()
.post(Entity.json(utilisateur));
Utilisateur entityFromDB = utilisateurdao.load(utilisateur.getName())
assertEquals(entityFromDB, utilisateur);
}
```
## Lisibilité du code
* Moins de 8 lignes.
* Le moins d'opération mentale possible pour le lecteur.
* Entrainements.
# Tests verts
## Du code testable
* Comment faire du code testable ? \
<i class="fa fa-arrow-right" aria-hidden="true"></i> cf. [Tout est testable](../02-mock/)
* Comment écrire de bons tests ? \
<i class="fa fa-arrow-right" aria-hidden="true"></i> ***Une partie de la réponse aujourd'hui.***
## Testable ?
```java
public long TicksElapsedFrom(int year) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime from = LocalDateTime.of(year, 1, 1, 0, 0);
return Duration.between(from, now).getSeconds();
}
```
. . .
**#NonRepeatable**
. . .
```java
public long TicksElapsedFrom(int year, LocalDateTime now) {
LocalDateTime from = LocalDateTime.of(year, 1, 1, 0, 0);
return Duration.between(from, now).getSeconds();
}
```
## Testable ?
```java
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getDisplayName(String prefix) {
name = prefix + " " + name;
return name;
}
}
```
. . .
**#SideEffect**
## Testable ?
```java
public void triche() {
if (this.tricheActivee) {
for (Bateau bateau : this.bateaux) {
System.out.println(bateau);
}
}
}
```
. . .
**#InputOutput**
. . .
```java
public String triche() {
String output = "";
if (this.tricheActivee) {
for (Bateau bateau : this.bateaux) {
output += bateau + "\n";
}
}
return output;
}
```
## Testable ?
```java
public String statement() {
double totalAmount = 0;
String result = "Rental Record for " + getName() + "\n";
for (Rental each : this.rentals) {
double thisAmount = each.determineAmount();
result += "\t" + each.getMovie().getTitle() + "\t" + thisAmount + "\n";
totalAmount += thisAmount;
}
result += "Amount owed is " + totalAmount + "\n";
return result;
}
```
. . .
**#NoSingleResponsability**
## Testable = Code propres
* Fonction pure :
* Sa valeur de retour est la même pour les mêmes arguments
* Son évaluation n'a pas d'effets de bord
* Limiter les mutations
* Des fonctions ou objets dédiés à l'I/O
* Une seul responsabilité (cf. SOLID)
## Bon ou mauvais test ?
```java
@Test
void testViewIsGettingUpdated() {
model.addSeller(new MarketSeller("John Doe", 500));
assertTrue(view.getMarketSellers().isEmpty());
model.attach(view);
model.addSeller(new MarketSeller("John Dodo", 500));
assertFalse(view.getMarketSellers().isEmpty());
assertEquals(view.getMarketSellers().size(), 2);
assertEquals(view.getMarketSellers().get(0).getName(), "John Doe");
assertEquals(view.getMarketSellers().get(1).getName(), "John Dodo");
}
```
## Qualité d'un test
* Il est rapide (quelques secondes max)
* Je peux le jouer 2 fois de suite il est encore vraie, même à plusieurs jours d'intervalles.
* Il est explicite, les destinataires de ce test peuvent le lire et le comprendre.
* Il ne test qu'une règle métier.
* Il est indépendant des autres tests :
* je peux jouer les tests dans le désordre
* je peux jouer tous les tests en même temps.
* Je peux restructurer mon code sans avoir à le changer
## Bon ou mauvais test ?
```java
@Test
public void stock_exchanges_test(){
Bourse bourse = new Bourse(800.0);
assertEquals(800.0, bourse.getAmount());
}
```
. . .
**#NonExplicit**
## Bon ou mauvais test ?
```java
@Test
void should_compute_interval_between_2_dates_in_good_order() {
LocalDate startDate = LocalDate.of(2015, 3, 2);
LocalDate endDate = LocalDate.of(2015, 3, 3);
Long days = IntervalDomain.between(startDate, endDate);
assertEquals(1, days);
}
```
. . .
**#Good**
## Bon ou mauvais test ?
```java
@Test
void should_raise_an_error_when_endDate_is_before_startDate() {
assertThrows(InvalidParameterException.class, () -> {
LocalDate startDate = LocalDate.of(2025, 3, 2);
LocalDate endDate = LocalDate.of(2020, 4, 3);
IntervalDomain.between(startDate, endDate);
});
}
```
. . .
**#Good**
## Bon ou mauvais test ?
```java
@Test
public void testSurpopulate(){
grille = new Grid();
grille.setAlive(1,1);
grille.setAlive(1,2);
grille.setAlive(0,1);
grille.setAlive(0,0);
grille.setAlive(2,2);
grille.playTurn();
assertFalse(grille.getCell(1,1).isAlive());
}
```
. . .
**#NonExplicit #Franglais**
## Bon ou mauvais test ?
```java
@Test
void un_depot_doit_incrementer_le_solde() {
CompteEnBanque compteDeBob = CompteEnBanque.creer("Bob");
compteDeBob.depot(12.2);
Assertions.assertEquals(12.2, compteDeBob.solde());
}
```
. . .
**#WarningRefactoring #WarningImmutability**
. . .
```java
@Test
void un_depot_doit_incrementer_le_solde() {
GivenAnAccount()
.with(euro(12.5))
.whenIDeposit(euro(10))
.thenTheSoldeShouldBe(euro(22.5));
}
```
## Bon ou mauvais tests ?
```java
@Test
public void marketPlaceTest() {
MarketPlace marketPlace = new MarketPlace();
Member alice = new Member("Alice", 1000);
Member bob = new Member("Bob", 1500);
marketPlace.addMember(alice);
assertEquals(marketPlace.toString(), "Member [name=Alice, money=1000]\n" );
marketPlace.addMember(bob);
assertEquals(marketPlace.toString(),
"Member [name=Alice, money=1000]\n" +
"Member [name=Bob, money=1500]\n" );
marketPlace.remove(alice);
assertEquals(marketPlace.toString(),"Member [name=Bob, money=1500]\n" );
}
```
. . .
**#NonExplicit #Multiples #TropLong #PascalCase**
## Bon ou mauvais tests ?
```java
@Test
public void ajouterUnProduitTest() {
myBourse.ajouterProduit(p1);
assertTrue(myBourse.produitDisponible(p1));
assertFalse(myBourse.produitDisponible(p2));
}
@Test
public void ajouterProduitsTest() {
myBourse.ajouterProduits(p2, p3);
assertTrue(myBourse.produitDisponible(p1));
assertTrue(myBourse.produitDisponible(p2));
assertTrue(myBourse.produitDisponible(p3));
}
```
. . .
**#WarningBeforeEach #TestsDependencies #NonExplicit**
## Bon ou mauvais tests ?
```java
@Test
void should_instance_member() {
Member alice = new Member("Alice",1000);
assertTrue(alice != null);
}
```
. . .
**#NonExplicit #ToujoursVrai**
## Bon ou mauvais tests ?
```java
@Test
void testConstructor(){
assertEquals(10, this.jdv.getTerrain().length);
assertEquals(10, this.jdv.getTerrain()[0].length);
}
```
. . .
**#InternalLeak #NotDemeter**
## Bon ou mauvais tests ?
```typescript
describe("Game", () => {
it("should add food when no stock", () => {
const game = new Game(100, 100)
game.players = []
game.foods = []
game.addFood(new Food())
expect(game.foods.length).toEqual(1)
})
})
```
. . .
**#WarningRefactoring #WarningImmutability #NoSingleResponsability**
## Bon ou mauvais test ?
```typescript
describe("Game", () => {
it("should add food when no stock", () => {
expect(addFood([]).length).toEqual(1)
})
it("should add food when no stock", () => {
expect(FoodStock.of([]).add().length).toEqual(1)
})
})
```
. . .
**#Good**
## Bon ou mauvais test ?
```java
public BookingResponse book() {
int place = new Random().nextInt(0,seats.length);
return new BookingResponse(BookingResponseStatus.OK,seats[place].getNumber());
}
```
. . .
**#NonRepeatable #NoSingleResponsability**
## Bon ou mauvais test ?
```java
@Test
public void shouldReturnTrue() {
SecretSanta s = new SecretSanta();
assertTrue(s.addSanta("toto"));
}
```
. . .
**#NonExplicit #PascalCase #MissingException**
## Bon ou mauvais test ?
:::: {.columns}
::: {.column width="50%"}
```java
public class TirageTest {
Tirage tirage;
String p1;
String p2;
@BeforeEach
public void initialize()
{
tirage = new Tirage();
p1 = "Théo";
p2 = "Nathan";
}
@Test
public void test_add()
{
assertTrue(tirage.add(p1));
assertTrue(tirage.add(p2));
```
:::
::: {.column width="50%"}
```java
assertFalse(tirage.add(p1));
}
@Test
public void test_affectation()
{
tirage.add(p1);
tirage.add(p2);
tirage.affectation();
assertTrue(
tirage.affectation().size()
==
tirage.size());
}
}
```
:::
::::
. . .
**#AssertEquals #TestsDependencies**
## Bon ou mauvais test ?
```java
public class PersonneTest {
Personne p1;
Personne p2;
Personne p3;
@BeforeEach
public void setUp() {
p1 = new Personne("Robert" );
p2 = new Personne("Jean");
p3 = new Personne("Pierre");
}
@Test
public void test_set_gifter(){
p1.setGifter(p2);
assertTrue(p1.getGifter().equals(p2));
}
}
```
. . .
**#TooComplicated**
## Bon ou mauvais test ?
```java
@Test
public void testBookProperty() {
Train t = new Train();
BookingResponse expected = t.getSeats()[4].getBr();
assertEquals(expected, t.book(SeatProperty.Duo));
}
```
. . .
**#NonExplicite**
## Bon ou mauvais test ?
```java
void should_return_a_seat_with_seat_property(){
Train train = new Train();
assertEquals(26, train.book(Duo).getSeat());
assertEquals(17, train.book(Square).getSeat());
}
```
. . .
**#TooTechnical**
## Bon ou mauvais test ?
```java
Train t = new Train();
@Test
void bookshould_return_place() {
BookingResponse response = new BookingResponse(BookingResponseStatus.OK, 17);
assertEquals(response,t.book());
}
@Test
void retourne_une_place_en_respectant_propriete() {
BookingResponse response = new BookingResponse(BookingResponseStatus.OK, 26);
assertEquals(response, t.book(SeatProperty.Duo));
}
@Test
void retourne_place_au_plus_proche() {
assertEquals(Seat.of(17, Square, Window), t.book(14));
}
```
. . .
**#NotExplicit #TestsDependencies**
## Bon ou mauvais test ?
```gherkin
Scenario: On retourne une place respectant la propriété en paramètre
Given un train
When on réserve une place avec une propriété SeatProperty.DUO
Then retourne une place avec la propriété SeatProperty.DUO
```
. . .
**#WarningRefactoring #TechnicalLeak**
# Anatomie d'un test
## Les étapes d'un test
* *Given* : un ensemble d'éléments observables permettant de décrire avec précision l'état de départ.
* *When* : **une** action
* *Then* : L'ensemble des éléments observables du système après l'action permettant de décrire avec précision l'état d'arrivée.
## 3 étapes
![](../includes/given-when-then.png)
## Given
:::: {.columns}
::: {.column width="50%"}
Étant donné un échiquier avec :
* le roi blanc en A5
* le roi noir en A7
* un pion blanc en B7
* une tour blanche en C7
* une tour noir en A8
Et c'est au blanc de jouer.
:::
::: {.column width="50%"}
![](../includes/given.png)
:::
::::
## When
Quand le joueur blanc déplace son pion de B7 à B8
et demande un cavalier noir.
## Then
:::: {.columns}
::: {.column width="50%"}
Alors Les blancs gagnent !
Échec et mat !
:::
::: {.column width="50%"}
![](../includes/then.png)
:::
::::
## Junit
```java
@Test
void should_promote_a_pawn_in_an_other_color () {
Chessboard chessboard = new Chessboard()
.with(King.of(White), "A5")
.with(King.of(Black), "A7")
.with(Pawn.of(White), "B7")
.with(Tower.of(White), "C7")
.with(Tower.of(Black), "A8")
chessboard.move("B7", "B8").request(Knight.of(Black))
assertEquals(chessboard.get("B8"), Knight.of(Black))
}
```
. . .
```java
@Test
void should_promote_a_pawn_in_an_other_color () {
Chessboard chessboard = new Chessboard().with(Pawn.of(White), "B7")
chessboard.move("B7", "B8").request(Knight.of(Black))
assertEquals(chessboard.get("B8"), Knight.of(Black))
}
```
## DSL
```java
@Test
void should_promote_a_pawn_in_an_other_color () {
GivenAChessboard().with(Pawn.of(White), "B7")
.whenMoveFrom("B7").to("B8").andRequestA(Black(Knight()))
.thenAt("B8").shouldFoundA(Black(Knight))
}
```
## Gherkin
```gherkin
Scenario: Promote a pawn in an other color
Given a chessboard with a "white pawn" in "B7"
When "white" player move from "B7" to "B8"
And request a "black knight"
Then in "B8" we can see a "black knight"
```
# Types vs Tests
## Tester le métier
```python
class Wallet:
def value(self, currency: Currency, rate: RateProvider) -> Amount:
...
```
```java
public class Wallet {
public Amount value(Currency currency, RateProvider rate) {
...
```
```typescript
export class Wallet {
public value(currency: Currency, rate: RateProvider): Amount {
...
```
## Tester aussi les paramètres
```python
class Wallet:
def value(self, currency, rate):
...
```
```python
def test_should_throw_bad_parameter_when_not_currency():
...
def test_should_throw_bad_parameter_when_not_rateProvider():
...
```
# Qualités d'un test
* Il est rapide (quelques secondes max)
* Je peux le jouer 2 fois de suite il est encore vraie, même à plusieurs jours d'intervalles.
* Il est explicite, les destinataires de ce test peuvent le lire et le comprendre.
* Il ne test qu'une règle.
* Il est indépendant des autres tests :
* je peux jouer les tests dans le désordre
* je peux jouer tous les tests en même temps.
* Je peux restructurer mon code sans avoir à le changer
## Qualité d'un exemple
Pour les tests qui doivent être lut par les biz, les exemples doivent être :
* ***précis*** : pour éviter les ambigüités, un bon exemple doit clairement définir l'état du système avant et après l'action. Le test doit être facile à reproduire.
* ***réaliste*** : utiliser de vraies exemples issue de la vraie vie qui permétrons aux lecteurs de mieux comprendre le contexte. `Ocean toto = ...` vs `Ocean atlantic = ...`
* ***simple*** à comprendre : évitez la tentation d'explorer toutes la combinatoire. Évitez d'utiliser des tableaux avec des dizaines de lignes et colonnes. Concentrez vous sur des cas précis et représentatifs.
## Non fonctionnel
On appel besoins non fonctionnels, les besoins implicites des utilisateurs évidents et les attentes des utilisateurs non évidents comme :
* Le service doit répondre en moins de 200ms
* Le programme doit être paramétrable par un unique fichier JSON
Les tests doivent aussi couvrir ces attentes.
# R4.02 - Qualité de développement # R4.02 - Qualité de développement
[Version en ligne](https://univlille.gitlab.io/iut-info/r4.02/cours/) [Version en ligne](http://univlille.gitlab.io/iut-info/r4.02/cours/)
## Fiche ressource ## Fiche ressource
...@@ -31,7 +31,8 @@ Tests, tests de non régression, tests d'intégration ...@@ -31,7 +31,8 @@ Tests, tests de non régression, tests d'intégration
## Déroulé du cours ## Déroulé du cours
* [Retour sur le TDD](./01-tdd/) * [Retour sur le TDD](./01-tdd/)
* [Tester le non testable](./02-mock/) * [Tout est testable](./02-mock/)
* [Il est beau mon test](./03-tests/)
## TPs ## TPs
......
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<junit.version>5.7.0</junit.version>
</properties>
<groupId>fr.univlille.iut.info.r402</groupId>
<artifactId>sample-code</artifactId>
<version>1.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package fr.univlille.iut.info.r402;
public record Cell(CellContent cellContent) {
}
package fr.univlille.iut.info.r402;
public enum CellContent {
Water, Fish, Shark;
}
package fr.univlille.iut.info.r402;
public class Ocean {
private final Cell[][] internalRepresentation;
public Ocean(int height, int width) {
this.internalRepresentation = new Cell[height][width];
}
public Cell[][] getInternalRepresentation() {
return internalRepresentation;
}
}
import fr.univlille.iut.info.r402.Cell;
import fr.univlille.iut.info.r402.CellContent;
import fr.univlille.iut.info.r402.Ocean;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static fr.univlille.iut.info.r402.CellContent.Fish;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class OceanTest {
@Test
void fish_should_move() {
new Ocean(3,3).getInternalRepresentation()[0][0] = new Cell(Fish);
assertEquals(Fish, new Ocean(3,3).getInternalRepresentation()[0][0].cellContent());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment