Skip to content
Snippets Groups Projects
Commit 772951c6 authored by Derrode Stéphane's avatar Derrode Stéphane :dromedary_camel:
Browse files

update sujet BE #2

parent 9d17c52c
No related branches found
No related tags found
No related merge requests found
......@@ -23,7 +23,7 @@ On doit pouvoir gérer le fond documentaire d'une bibliothèque identifiée par
1. Notre application doit être capable de gérer des lecteurs. Chacun d’eux est caractérisé par :
- Son nom complet (nom et prénom)
- Son nom complet (en une seule chaîne)
- Son adresse,
- Un numéro (entier positif attribué de manière unique par les bibliothécaires).
......
......@@ -4,7 +4,7 @@
# BE #2 : Modélisation de formes géométriques
Le but de ce BE est d'illustrer le concept d'héritage de la programmation objet, en concevant un module pour manipuler des formes géométriques avec _Python_. Vous commencerez par définir les classes et leurs attributs, puis implémenterez les méthodes, et les validerez avec des tests.
Le but de ce BE est d'illustrer le concept d'héritage de la programmation objet, en concevant un module pour manipuler des formes géométriques avec Python. Vous commencerez par définir les classes et leurs attributs, puis implémenterez les méthodes, et les validerez avec des tests.
---
......@@ -18,7 +18,7 @@ Les formes géométriques sont représentées par des classes, et l'héritage se
<center><img src="figures/formes.svg" style="width:70%"/></center>
__Exercice 1 -__ Représentez les 3 classes dans un diagramme de classes UML (_voir [diagrams.net](https://app.diagrams.net) pour dessiner en ligne, avec l'onglet UML sur la gauche de l'interface_). Il est recommandé de commencer les noms des classes par une majuscule et les attributs par une minuscule. Les attributs devraient-ils être publics ou privés ?
__Exercice 1 -__ Représentez les 3 classes dans un diagramme de classes UML (_voir [diagrams.net](https://app.diagrams.net) pour dessiner en ligne, avec l'onglet UML sur la gauche de l'interface_). Il est recommandé de commencer les noms des classes par une majuscule et les attributs par une minuscule. Durant tout ce BE on considèrera uniquement des attributs privés.
Les attributs `x` et `y` étant partagés par les trois classes et le cercle étant un cas particulier d'ellipse, on introduit l'héritage pour les regrouper. Toutes les formes géométriques hériteront d'une même classe __Forme__, et le cercle héritera de l'ellipse. L'intérêt de ces relations d'héritage est double :
......@@ -28,7 +28,13 @@ Les attributs `x` et `y` étant partagés par les trois classes et le cercle ét
__Exercice 2 -__ Mettez à jour le diagramme UML en incluant la classe __Forme__ et les relations d'héritage. Seuls les attributs seront inclus pour le moment.
__Exercice 3 -__ Complétez le diagramme UML avec ces méthodes. Les constructeurs devront également être renseignés (méthode `__init__` en _Python_), ainsi que les méthodes d'affichage (méthode `__str__`).
Enfin, on vous demande de supporter a minima pour chaque forme les méthodes suivantes :
* `translation(dx, dy)`, qui effectue une translation selon un vecteur donné.
* `contient_point(x, y)`, qui renvoie `True` si et seulement si le point donné est à l'intérieur de la forme ou sur sa frontière.
* `redimension_par_points(x0, y0, x1, y1)`, qui redimensionne la forme telle qu'elle soit incluse dans le rectangle de coins (`x0`, `y0`) et (`x1`, `y1`). Dans le cas du cercle, il faudra également qu'il soit le plus proche du premier coin. Cette méthode est utile par exemple dans [diagrams.net](https://app.diagrams.net) pour le tracé de formes par appui-déplacement de souris.
__Exercice 3 -__ Complétez le diagramme UML avec ces méthodes. Les constructeurs devront également être renseignés (méthode `__init__` en _Python_), ainsi que les méthodes d'accès (les fameux _getter_/_setter_) et d'affichage (méthode `__str__`).
__Exercice 4 -__ Écrivez un squelette de code correspondant à votre diagramme UML, dans un fichier _formes.py_. Seuls les constructeurs devront être implémentés. À l'intérieur des autres méthodes, vous mettrez l'instruction `pass` de _Python_ (qui ne fait rien mais vous rappelle que le code est inachevé).
......@@ -62,11 +68,11 @@ def test_Ellipse():
def test_Cercle():
c = Cercle(10, 20, 30)
str(c)
assert e.contient_point(0, 0)
assert not e.contient_point(-19, -9)
e.redimension_par_points(100, 200, 1100, 700)
assert e.contient_point(500, 500)
assert not e.contient_point(599, 500)
assert c.contient_point(0, 0)
assert not c.contient_point(-19, -9)
c.redimension_par_points(100, 200, 1100, 700)
assert c.contient_point(500, 500)
assert not c.contient_point(599, 500)
if __name__ == '__main__':
test_Rectangle()
......@@ -84,11 +90,11 @@ La vérification de cette condition est faite une fois au moment de son exécuti
__Exercice 5 -__ Implémentez les méthodes d'affichage (`__str__`) de chacune des classes dans _formes.py_. Vous pourrez vérifier leur bon fonctionnement en exécutant _formes.py_ (bouton `Run File - F5`), puis par exemple avec une commande `print(Rectangle(0, 0, 10, 10))` dans la console _IPython_.
__Exercice 6 -__ Implémentez les méthodes d'accès (les fameux _getter_/_setter_) pour les champs privés de chacune des classes. Pour vérifier que les champs sont bien privés, le code suivant __doit__ échouer avec une erreur `AttributeError` :
__Exercice 6 -__ Implémentez les méthodes d'accès (_getter_/_setter_) pour les champs privés de chacune des classes. Pour vérifier que les champs sont bien privés, le code suivant __doit__ échouer avec une erreur `AttributeError` :
```python
r = Rectangle(0, 0, 10, 10)
print(r.__l, r.__h)
print(r.__x, r.__y, r.__w, r.__h)
```
__Exercice 7 -__ Implémentez les méthodes `contient_point` des deux sous-classes. Vous vérifierez que les deux premiers `assert` des méthodes de test ne déclenchent pas d'erreur.
......@@ -141,23 +147,4 @@ La rédaction de tests unitaires consiste souvent à anticiper les bugs courants
__Exercice 10 -__ Dessinez une ellipse dans votre logiciel de dessin, et représentez tous les points qu'il convient de tester avec `contient_point`. Pour chaque point (ou groupe de points), indiquez le type de bug qu'il vise en particulier. Implémentez ces tests dans _test_formes.py_.
__Exercice 11 -__ Dessinez une forme issue de votre troisième classe dans le logiciel de dessin, et choisissez les points qu'il faudra tester. Implémentez une nouvelle méthode de tests pour cette classe dans _test_formes.py_.
<!-- ## Pour aller plus loin
Lorsque votre programme utilise un grand nombre de tests unitaires, il est possible d'automatiser leur collecte, leur exécution, et l'affichage d'un rapport synthétique. On utilisera alors le module [_pytest_](https://docs.pytest.org/en/stable/) pour Python.
❗ Son installation nécessite que vous ayez installé Anaconda pour l'utilisateur de la machine, et non global au système. Il suffit alors d'ouvrir un terminal d'Anaconda (sous Windows, Menu Démarrer -> Anaconda -> Anaconda Prompt, sous Linux/Mac le terminal de base suffit), et d'y lancer la commande suivante :
```sh
conda install pytest
```
Si vous rencontrez une erreur comme `conda: command not found`, c'est que l'exécutable `conda` n'est présent dans aucun des dossiers visités par le terminal (essayez `echo %PATH%` pour en afficher la liste sous Windows, et `echo $PATH` sous Linux/Mac). Sous Windows, vérifiez que vous ouvrez bien le terminal d'Anaconda (pas le terminal par défaut du système). Sous Linux/Mac, la commande `export PATH=~/anaconda3/bin:/usr/local/anaconda3/bin:/usr/anaconda3/bin:$PATH` va ajouter (temporairement) une liste de répertoires usuels à la liste de recherche.
__Exercice 12 -__ Vérifiez que _pytest_ est installé en exécutant la commande `import pytest` qui ne doit pas renvoyer d'erreur. Ensuite exécutez la commande `pytest.main()`. Combien de fichiers ont été "collectés" ? Combien de tests ont réussi ? Combien ont échoué ?
__Exercice 13 -__ [pytest.raises](https://docs.pytest.org/en/stable/assert.html#assertions-about-expected-exceptions) permet de vérifier qu'un bloc de code déclenche une exception (`raises` ne fait rien si le code échoue, et échoue si le code ne déclenche pas d'exception). Lisez les exemples de la documentation et ajoutez des tests pour vérifier que les variables privées sont inaccessibles de l'extérieur de chaque classe.
-->
\ No newline at end of file
__Exercice 11 -__ Dans le cas du cercle, la différence principale avec l'ellipse est la méthode `redimension_par_points` qui nécessite de placer le centre du cercle au plus près du premier point. Proposez des tests qui permettent de vérifier que la méthode positionne toujours correctement le cercle dans la boîte englobante d'entrée.
File moved
File moved
File moved
File moved
File moved
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment