Logo
  • A propos
  • Blog
  • Services
  • Media
  • Contact
Contactez-nous !

Factory Pattern : Réduire la duplication et générer vos objets de test efficacement

Date publication
Sep 9, 2025

Factory Pattern : Réduire la duplication et générer vos objets de test efficacement

Cet article est le deuxième de notre série dédiée aux design patterns pour l'automatisation des tests. Après avoir posé les bases avec le Page Object Model, explorons comment le Factory Pattern peut transformer la création de vos objets de test et être un allié précieux pour simplifier et centraliser la création de vos objets de test.

image

Quand la création devient un art

Imaginez-vous en train de créer manuellement chaque objet de test, répétant sans cesse les mêmes configurations, les mêmes initialisations... Cette approche artisanale devient rapidement un cauchemar de maintenance. C'est précisément là que le Factory Pattern entre en scène, transformant la création chaotique d'objets en un processus élégant et centralisé.

Le Factory Pattern, l'un des patterns de création les plus utilisés en génie logiciel, trouve une application particulièrement puissante dans l'automatisation des tests. Il nous permet de déléguer la création d'objets complexes à des classes spécialisées, garantissant cohérence et flexibilité.

Qu'est-ce que le Factory Pattern ?

Le Factory Pattern est un pattern de création qui fournit une interface pour créer des objets sans spécifier explicitement leur classe concrète. Dans le contexte de l'automatisation des tests, il centralise et standardise la création d'objets comme les drivers, les données de test, ou les Page Objects.

Objectif principal : Centraliser la création d'objets de test

Le Factory Pattern répond à plusieurs besoins cruciaux :

  • Centralisation : Un point unique pour la création d'objets similaires
  • Abstraction : Masquer la complexité de l'instanciation
  • Flexibilité : Faciliter l'ajout de nouvelles variantes
  • Réutilisabilité : Éviter la duplication de code de création

Architecture du Factory Pattern

image

Exemple concret : Factory pour tests multi-navigateurs

L'un des cas d'usage les plus répandus du Factory Pattern en automatisation est la gestion des WebDrivers pour les tests multi-navigateurs. Voici comment l'implémenter efficacement :

Sans Factory Pattern (approche répétitive) :

WebDriver driver;

if (browser.equals("chrome")) {
    driver = new ChromeDriver();
} else if (browser.equals("firefox")) {
    driver = new FirefoxDriver();
} else {
    driver = new EdgeDriver();
}

// Duplication pour chaque navigateur... 😰
// Ce code est répété dans plusieurs tests = maintenance compliquée.

Avec Factory Pattern (approche élégante) :

Résultat : un seul endroit à modifier si vous ajoutez Safari, Opera, ou un mode headless.

Factory avancé : Création de données de test

Le Factory Pattern excelle également dans la création de données de test complexes :

Architecture complète avec Factory Pattern

image

Bonnes pratiques essentielles

1. Interface claire et cohérente

Définissez des interfaces claires pour vos factories :

// ✅ Interface simple et expressive
public interface TestDataFactory<T> {
    T createValid();
    T createInvalid();
    T createWithCustomData(Map<String, Object> customData);
    List<T> createBatch(int count);
}

2. Gestion des erreurs robuste

Implémentez une gestion d'erreur appropriée :

3. Configuration externalisée

Utilisez des fichiers de configuration pour la flexibilité :

4. Pattern Singleton pour les factories

Optimisez les performances avec le pattern Singleton :

5. Factory Registry pour l'extensibilité

Permettez l'enregistrement dynamique de nouvelles factories :

FAQ

Q: Quand utiliser le Factory Pattern dans mes tests ?

R: Utilisez-le dès que vous créez plusieurs instances d'objets similaires avec des variations (différents navigateurs, jeux de données, configurations). C'est particulièrement utile pour les WebDrivers, les données de test, et les Page Objects avec paramètres.

Q: Factory Pattern vs Builder Pattern, quelle différence ?

R: Le Factory crée des objets complets d'un coup, tandis que le Builder construit des objets étape par étape. Factory = "créer différents types d'objets", Builder = "créer des objets complexes progressivement".

Q: Comment gérer les dépendances dans les factories ?

R: Utilisez l'injection de dépendances ou passez les dépendances en paramètres. Évitez les dépendances hardcodées dans les factories pour maintenir la flexibilité.

Q: Le Factory Pattern impacte-t-il les performances ?

R: L'impact est généralement négligeable. L'abstraction apporte plus de bénéfices (maintenabilité, flexibilité) que le coût minimal en performance. Pour optimiser, utilisez des caches ou le pattern Singleton si approprié.

Q: Comment tester mes factories ?

R: Créez des tests unitaires qui vérifient que chaque factory retourne le bon type d'objet avec les bonnes propriétés. Testez aussi la gestion des cas d'erreur et des paramètres invalides.

Q: Peut-on combiner Factory avec d'autres patterns ?

R: Absolument ! Factory se combine excellemment avec Singleton (pour l'instance unique), et Builder (pour des objets complexes).

Q: Peut-on utiliser plusieurs factories dans un même framework ?

R: Oui. Par exemple, une WebDriverFactory pour les navigateurs et une DataFactory pour générer des données de test.

A retenir

Le Factory Pattern est un outil simple mais puissant pour rendre vos tests plus robustes, maintenables et évolutifs.

Il permet de centraliser la création d’objets, d’éviter la duplication et d’ouvrir la voie à des frameworks de test professionnels.

Dans le prochain article, nous explorerons le Facade Pattern et comment il peut simplifier vos scénarios de test les plus complexes en masquant la complexité technique derrière une interface élégante.

Plus d’articles comme celui-ci

Combiner les Patterns : Architecturer un framework de test solide et évolutif
Combiner les Patterns : Architecturer un framework de test solide et évolutif
Oct 7, 2025
Screenplay Pattern : Structurer vos tests pour plus de lisibilité et de robustesse
Screenplay Pattern : Structurer vos tests pour plus de lisibilité et de robustesse
Sep 30, 2025
Builder Pattern : Créer des objets de test complexes avec clarté
Builder Pattern : Créer des objets de test complexes avec clarté
Sep 23, 2025
Facade Pattern : Cacher la complexité de vos scénarios automatisés
Facade Pattern : Cacher la complexité de vos scénarios automatisés
Sep 16, 2025
Factory Pattern : Réduire la duplication et générer vos objets de test efficacement
Factory Pattern : Réduire la duplication et générer vos objets de test efficacement
Sep 9, 2025
Page Object Model : La base solide pour toute automatisation UI
Page Object Model : La base solide pour toute automatisation UI
Sep 2, 2025
Logo

Accueil

Blog

Newsletters

Podcasts

Vidéos

Qui suis-je ?

Shift Op Solutions

Mentorat

Formations

Etat des Lieux

Contact

Copyright © Jean-François Fresi 2024 - Site créé en nocode.

LinkedInYouTubeSpotifyRSS
// Factory
public class WebDriverFactory {

    public static WebDriver create(String browser) {
        switch (browser.toLowerCase()) {
            case "chrome":
                return new ChromeDriver();
            case "firefox":
                return new FirefoxDriver();
            case "edge":
                return new EdgeDriver();
            default:
                throw new IllegalArgumentException("Navigateur non supporté : " + browser);
        }
    }
}

// Utilisation dans les tests
WebDriver driver = WebDriverFactory.create("chrome");
LoginPage login = new LoginPage(driver);
login.loginAs("jean@test.com", "123456");
// Factory pour générer des utilisateurs de test
public class TestUserFactory {
    private static final Faker faker = new Faker();
    
    public static User createValidUser() {
        return User.builder()
                .email(faker.internet().emailAddress())
                .firstName(faker.name().firstName())
                .lastName(faker.name().lastName())
                .password("ValidPassword123!")
                .age(faker.number().numberBetween(18, 65))
                .build();
    }
    
    public static User createAdminUser() {
        return User.builder()
                .email("admin@testdomain.com")
                .firstName("Admin")
                .lastName("User")
                .password("AdminPass123!")
                .role(UserRole.ADMIN)
                .age(35)
                .build();
    }
    
    public static User createInvalidUser() {
        return User.builder()
                .email("invalid-email")
                .firstName("")
                .lastName(null)
                .password("123")  // Mot de passe faible
                .age(10)  // Âge invalide
                .build();
    }
    
    public static List<User> createUserBatch(int count, UserType type) {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            switch (type) {
                case VALID:
                    users.add(createValidUser());
                    break;
                case ADMIN:
                    users.add(createAdminUser());
                    break;
                case INVALID:
                    users.add(createInvalidUser());
                    break;
            }
        }
        return users;
    }
}

// Utilisation dans les tests
@Test
public void testUserRegistrationWithValidData() {
    User testUser = TestUserFactory.createValidUser();
    
    RegistrationPage registrationPage = new RegistrationPage(driver);
    registrationPage.fillRegistrationForm(testUser);
    
    Assert.assertTrue(registrationPage.isRegistrationSuccessful());
}
public class DriverFactoryManager {
    public static WebDriver createDriver(BrowserType browserType) {
        try {
            WebDriverFactory factory = factories.get(browserType);
            if (factory == null) {
                throw new UnsupportedBrowserException(
                    "Browser not supported: " + browserType
                );
            }
            return factory.createDriver();
        } catch (Exception e) {
            logger.error("Failed to create driver for browser: " + browserType, e);
            throw new DriverCreationException("Driver creation failed", e);
        }
    }
}
// config.properties
browser.default=chrome
browser.headless=true
timeout.implicit=10
timeout.explicit=30

// Factory utilisant la configuration
public class ConfigurableDriverFactory {
    private static final Properties config = loadConfiguration();
    
    public static WebDriver createDriver() {
        String browser = config.getProperty("browser.default", "chrome");
        boolean headless = Boolean.parseBoolean(config.getProperty("browser.headless", "false"));
        
        return createDriver(BrowserType.valueOf(browser.toUpperCase()), headless);
    }
}
public class WebDriverFactoryManager {
    private static volatile WebDriverFactoryManager instance;
    private final Map<BrowserType, WebDriverFactory> factories;
    
    private WebDriverFactoryManager() {
        factories = initializeFactories();
    }
    
    public static WebDriverFactoryManager getInstance() {
        if (instance == null) {
            synchronized (WebDriverFactoryManager.class) {
                if (instance == null) {
                    instance = new WebDriverFactoryManager();
                }
            }
        }
        return instance;
    }
}
public class FactoryRegistry {
    private static final Map<String, WebDriverFactory> registeredFactories = new ConcurrentHashMap<>();
    
    public static void registerFactory(String name, WebDriverFactory factory) {
        registeredFactories.put(name, factory);
    }
    
    public static WebDriver createDriver(String factoryName) {
        WebDriverFactory factory = registeredFactories.get(factoryName);
        if (factory == null) {
            throw new IllegalArgumentException("Unknown factory: " + factoryName);
        }
        return factory.createDriver();
    }
}