Solution tests
3. Premiers tests
Date.java (version incorrecte)
package gloo.date; public class Date { private int jour; private int mois; private int annee; public Date( int jour, int mois, int annee ) { super(); this.jour = jour; this.mois = mois; this.annee = annee; } public Date lendemain() { return new Date( jour + 1, mois, annee ); } }
TestDateLendemainSpec.java
package gloo.date.test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import gloo.date.Date; class TestDateLendemainSpec { @Test void testLendemainNotNull() { Date date = new Date( 18, 1, 2022 ); assertNotNull( date.lendemain() ); } @Test void testLendemainNotSame() { Date date = new Date( 18, 1, 2022 ); assertNotSame( date, date.lendemain() ); } @Test void testLendemainSimple() { Date today = new Date( 18, 1, 2022 ); Date tomorrow = new Date( 19, 1, 2022 ); assertEquals( tomorrow, today.lendemain() ); } }
Date.java (version corrigée)
package gloo.date; public class Date { private int jour; private int mois; private int annee; public Date( int jour, int mois, int annee ) { super(); this.jour = jour; this.mois = mois; this.annee = annee; } // hashCode() n'est pas utilisé dans cet exercice, mais si on demande à Eclipse de // générer equals(), il génère aussi hashcode(). @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + annee; result = prime * result + jour; result = prime * result + mois; return result; } @Override public boolean equals( Object obj ) { if( this == obj ) return true; if( obj == null ) return false; if( getClass() != obj.getClass() ) return false; Date other = ( Date ) obj; if( annee != other.annee ) return false; if( jour != other.jour ) return false; if( mois != other.mois ) return false; return true; } public Date lendemain() { return new Date( jour + 1, mois, annee ); } }
4. Prise en compte de la durée des mois
Date.java
package gloo.date; public class Date { private static final int NOMBRE_JOURS_MAX = 31; private static final int NOMBRE_MOIS = 12; private int jour; private int mois; private int annee; public Date( int jour, int mois, int annee ) { super(); this.jour = jour; this.mois = mois; this.annee = annee; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + annee; result = prime * result + jour; result = prime * result + mois; return result; } @Override public boolean equals( Object obj ) { if( this == obj ) return true; if( obj == null ) return false; if( getClass() != obj.getClass() ) return false; Date other = ( Date ) obj; if( annee != other.annee ) return false; if( jour != other.jour ) return false; if( mois != other.mois ) return false; return true; } public Date lendemain() { int j = jour + 1; int m = mois; int a = annee; if( j > nombreJoursDansMois( mois, annee )) { j = 1; m += 1; if( m > NOMBRE_MOIS ) { m = 1; a += 1; } } return new Date( j, m, a ); } private static int nombreJoursDansMois( int mois ) { return switch( mois ) { case 1, 3, 5, 7, 8, 10, 12 -> NOMBRE_JOURS_MAX; case 2 -> NOMBRE_JOURS_MAX - 3; case 4, 6, 9, 11 -> NOMBRE_JOURS_MAX - 1; default -> throw new IllegalArgumentException( "Unexpected value: " + mois ); }; } }
TestDateLendemainFinMois.java
package gloo.date.test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import gloo.date.Date; class TestDateLendemainFinMois { @Test void testDateFinJanvier() { Date actual = new Date( 31, 1, 2022 ); Date expected = new Date( 1, 2, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinFevrier() { Date actual = new Date( 28, 2, 2022 ); Date expected = new Date( 1, 3, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinMars() { Date actual = new Date( 31, 3, 2022 ); Date expected = new Date( 1, 4, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinAvril() { Date actual = new Date( 30, 4, 2022 ); Date expected = new Date( 1, 5, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinMai() { Date actual = new Date( 31, 5, 2022 ); Date expected = new Date( 1, 6, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinJuin() { Date actual = new Date( 30, 6, 2022 ); Date expected = new Date( 1, 7, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinJuillet() { Date actual = new Date( 31, 7, 2022 ); Date expected = new Date( 1, 8, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinAout() { Date actual = new Date( 31, 8, 2022 ); Date expected = new Date( 1, 9, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinSeptembre() { Date actual = new Date( 30, 9, 2022 ); Date expected = new Date( 1, 10, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinOctobre() { Date actual = new Date( 31, 10, 2022 ); Date expected = new Date( 1, 11, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinNovembre() { Date actual = new Date( 30, 11, 2022 ); Date expected = new Date( 1, 12, 2022 ); assertEquals( expected, actual.lendemain() ); } @Test void testDateFinDecembre() { Date actual = new Date( 31, 12, 2022 ); Date expected = new Date( 1, 1, 2023 ); assertEquals( expected, actual.lendemain() ); } }
5. Prise en compte des années bisextiles
Date.java
package gloo.date; public class Date { private static final int NOMBRE_JOURS_MAX = 31; private static final int NOMBRE_MOIS = 12; private int jour; private int mois; private int annee; public Date( int jour, int mois, int annee ) { super(); this.jour = jour; this.mois = mois; this.annee = annee; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + annee; result = prime * result + jour; result = prime * result + mois; return result; } @Override public boolean equals( Object obj ) { if( this == obj ) return true; if( obj == null ) return false; if( getClass() != obj.getClass() ) return false; Date other = ( Date ) obj; if( annee != other.annee ) return false; if( jour != other.jour ) return false; if( mois != other.mois ) return false; return true; } public Date lendemain() { int j = jour + 1; int m = mois; int a = annee; if( j > nombreJoursDansMois( mois, annee )) { j = 1; m += 1; if( m > NOMBRE_MOIS ) { m = 1; a += 1; } } return new Date( j, m, a ); } private static int nombreJoursDansMois( int mois, int annee ) { return switch( mois ) { case 1, 3, 5, 7, 8, 10, 12 -> NOMBRE_JOURS_MAX; case 2 -> NOMBRE_JOURS_MAX - ( estBissextile( annee ) ? 2 : 3 ); case 4, 6, 9, 11 -> NOMBRE_JOURS_MAX - 1; default -> throw new IllegalArgumentException( "Unexpected value: " + mois ); }; } private static boolean estBissextile( int annee ) { return annee % 400 == 0 || (( annee % 4 == 0 ) && ( annee % 100 != 0 )); } }
TestAnneeBissextile.java
package gloo.date.test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import gloo.date.Date; class TestAnneeBissextile { @Test void testAnneeBissectile2008() { Date actual = new Date( 28, 2, 2008 ); Date expected = new Date( 29, 2, 2008 ); assertEquals( expected, actual.lendemain() ); } @Test void testAnneeNonBissectile1900() { Date actual = new Date( 28, 2, 1900 ); Date expected = new Date( 1, 3, 1900 ); assertEquals( expected, actual.lendemain() ); } @Test void testAnneeBissectile2000() { Date actual = new Date( 28, 2, 2000 ); Date expected = new Date( 29, 2, 2000 ); assertEquals( expected, actual.lendemain() ); } }
6. Validation des dates initiales
Date.java
package gloo.date; public class Date { private static final int NOMBRE_JOURS_MAX = 31; private static final int NOMBRE_MOIS = 12; private int jour; private int mois; private int annee; public Date( int jour, int mois, int annee ) { super(); verifieArguments( jour, mois, annee ); this.jour = jour; this.mois = mois; this.annee = annee; } private static void verifieArguments( int jour, int mois, int annee ) { if( jour <= 0 ) throw new IllegalArgumentException( "jour doit être >= 1" ); // Il faut vérifier la validité de mois et annee avant d'utiliser nombreJoursDansMois if( mois <= 0 ) throw new IllegalArgumentException( "mois doit être >= 1" ); if( mois > NOMBRE_MOIS ) throw new IllegalArgumentException( "mois doit être <= 12" ); if( annee <= 0 ) throw new IllegalArgumentException( "annee doit être >= 1" ); if( jour > nombreJoursDansMois( mois, annee )) throw new IllegalArgumentException( "jour doit être >= 1" ); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + annee; result = prime * result + jour; result = prime * result + mois; return result; } @Override public boolean equals( Object obj ) { if( this == obj ) return true; if( obj == null ) return false; if( getClass() != obj.getClass() ) return false; Date other = ( Date ) obj; if( annee != other.annee ) return false; if( jour != other.jour ) return false; if( mois != other.mois ) return false; return true; } public Date lendemain() { int j = jour + 1; int m = mois; int a = annee; if( j > nombreJoursDansMois( mois, annee )) { j = 1; m += 1; if( m > NOMBRE_MOIS ) { m = 1; a += 1; } } return new Date( j, m, a ); } private static int nombreJoursDansMois( int mois, int annee ) { return switch( mois ) { case 1, 3, 5, 7, 8, 10, 12 -> NOMBRE_JOURS_MAX; case 2 -> NOMBRE_JOURS_MAX - ( estBissextile( annee ) ? 2 : 3 ); case 4, 6, 9, 11 -> NOMBRE_JOURS_MAX - 1; default -> throw new IllegalArgumentException( "Unexpected value: " + mois ); }; } private static boolean estBissextile( int annee ) { return annee % 400 == 0 || (( annee % 4 == 0 ) && ( annee % 100 != 0 )); } }
TestConstructeurDate.java
package gloo.date.test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import gloo.date.Date; class TestConstructeurDate { @Test void testConstructeurDateValide() { assertDoesNotThrow( () -> { new Date( 18, 1, 2022 ); } ); } @Test void testConstructeurDateInvalideJourNegatif() { assertThrows( IllegalArgumentException.class, () -> { new Date( -10, 2, 2020 ); } ); } @Test void testConstructeurDateInvalideJourNul() { assertThrows( IllegalArgumentException.class, () -> { new Date( 0, 12, 2026 ); } ); } @Test void testConstructeurDateFinJanvier() { assertDoesNotThrow( () -> { new Date( 31 , 1, 4126 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 1, 4126 ); } ); } @Test void testConstructeurDateFinFevrier() { assertDoesNotThrow( () -> { new Date( 28 , 2, 1111 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 28 + 1, 2, 1111 ); } ); } @Test void testConstructeurDateFinFevrierBissextile() { assertDoesNotThrow( () -> { new Date( 29 , 2, 2008 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 29 + 1, 2, 2008 ); } ); } @Test void testConstructeurDateFinMars() { assertDoesNotThrow( () -> { new Date( 31 , 3, 3 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 3, 3 ); } ); } @Test void testConstructeurDateFinAvril() { assertDoesNotThrow( () -> { new Date( 30 , 4, 9999 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 30 + 1, 4, 9999 ); } ); } @Test void testConstructeurDateFinMai() { assertDoesNotThrow( () -> { new Date( 31 , 5, 5555 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 5, 5555 ); } ); } @Test void testConstructeurDateFinJuin() { assertDoesNotThrow( () -> { new Date( 30 , 6, 6 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 30 + 1, 6, 6 ); } ); } @Test void testConstructeurDateFinJuillet() { assertDoesNotThrow( () -> { new Date( 31 , 7, 123 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 7, 123 ); } ); } @Test void testConstructeurDateFinAout() { assertDoesNotThrow( () -> { new Date( 31 , 8, 1 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 8, 1 ); } ); } @Test void testConstructeurDateFinSeptembre() { assertDoesNotThrow( () -> { new Date( 30 , 9, 2020 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 30 + 1, 9, 2020 ); } ); } @Test void testConstructeurDateFinOctobre() { assertDoesNotThrow( () -> { new Date( 31 , 10, 4040 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 10, 4040 ); } ); } @Test void testConstructeurDateFinNovembre() { assertDoesNotThrow( () -> { new Date( 30 , 11, 6060 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 30 + 1, 11, 6060 ); } ); } @Test void testConstructeurDateFinDecembre() { assertDoesNotThrow( () -> { new Date( 31 , 12, 12 ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( 31 + 1, 12, 12 ); } ); } @Test void testDateInvalideMoisNegatif() { assertThrows( IllegalArgumentException.class, () -> { new Date( 10, -12, 1515 ); } ); } @Test void testDateInvalideMoisNul() { assertThrows( IllegalArgumentException.class, () -> { new Date( 31, 0, 999 ); } ); } @Test void testDateInvalideMoisTropGrand() { assertThrows( IllegalArgumentException.class, () -> { new Date( 1, 13, 1 ); } ); } @Test void testDateInvalideAnneeNegative() { assertThrows( IllegalArgumentException.class, () -> { new Date( 20, 2, -1 ); } ); } }
7. Meilleure écriture des tests
TestConstructeurDate.java
package gloo.date.test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import gloo.date.Date; class TestConstructeurDate { @Test void testConstructeurDateValide() { assertDoesNotThrow( () -> { new Date( 18, 1, 2022 ); } ); } @Test void testConstructeurDateInvalideJourNegatif() { assertThrows( IllegalArgumentException.class, () -> { new Date( -10, 2, 2020 ); } ); } @Test void testConstructeurDateInvalideJourNul() { assertThrows( IllegalArgumentException.class, () -> { new Date( 0, 12, 2026 ); } ); } @ParameterizedTest @CsvSource({ "31, 1, 4126", "28, 2, 1111", "29, 2, 2008", "31, 3, 3", "30, 4, 9999", "31, 5, 5555", "30, 6, 6", "31, 7, 123", "31, 8, 1", "30, 9, 2020", "31, 10, 4040", "30, 11, 6060", "31, 12, 12" }) void testConstructeurDateFinMois( int j, int m, int a ) { assertDoesNotThrow( () -> { new Date( j, m, a ); } ); assertThrows( IllegalArgumentException.class, () -> { new Date( j + 1, m, a ); } ); } @Test void testDateInvalideMoisNegatif() { assertThrows( IllegalArgumentException.class, () -> { new Date( 10, -12, 1515 ); } ); } @Test void testDateInvalideMoisNul() { assertThrows( IllegalArgumentException.class, () -> { new Date( 31, 0, 999 ); } ); } @Test void testDateInvalideMoisTropGrand() { assertThrows( IllegalArgumentException.class, () -> { new Date( 1, 13, 1 ); } ); } @Test void testDateInvalideAnneeNegative() { assertThrows( IllegalArgumentException.class, () -> { new Date( 20, 2, -1 ); } ); } }

© 2020-22 CentraleSupélec