0

I'm having the following test classes. I'm wondering if there's a design pattern that can reduce the code duplication in the following scenario.

public abstract class BaseTestClass {

    protected String color;

    protected String type;

    protected Product product;

    abstract void setColor();

    abstract void setClothType();

    abstract Product createTheProduct();

    @BeforeClass
    public void setUp(){
      // there're partial overlaps of "setup" for pants and shirts
    }

    @Test
    public void doATest(){
        testSomethingWithProduct(product);
    }

    @AfterClass
    public void tearDown(){
      // there're partial overlaps of "tearDown" for pants and shirts
    }
}


public class TestBlueShirt extends BaseTestClass {

    @Override
    void setColor() {
        this.color = "blue";
    }

    @Override
    void setClothType() {
        this.type = "shirt";
    }

    @Override
    Product createTheProduct() {
       setColor();
       setClothType();
       // create this.product based on color and type...
    }
}

public class TestRedShirt extends BaseTestClass {}
public class TestBluePants extends BaseTestClass {}
public class TestRedPants extends BaseTestClass {}
...

You will find there's duplicated code when setting colors for the same type of cloth or when setting the type for the same color. I'm wondering how I can have a concrete class that can produce something like Class<T> (RedShirt, BlueShirt, RedPants, etc.), and based on Class<T>, I can directly implement @Test in the base class. So I can avoid code duplication as much as I can.

something like:

public abstract class BaseTestClass {

    protected Product product;

    abstract Product createTheProduct(Class<T> ...);

    @BeforeClass
    public void setUp(){
      setUpBasedOnProduct(Class<T> ...);

    }

    @Test
    public void doATest(){
        testSomethingWithProduct(product);
    }

    @AfterClass
    public void tearDown(){
        tearDownBasedOnProduct(Class<T> ...);
    }
}

import ...ClassGenerator

public class TestBlueShirt extends BaseTestClass {
    
    @Override
    createTheProduct(ClassGenerator.createClass("blue", "shirt"));
}

Thanks in advance!

noobie2023
  • 721
  • 8
  • 25

1 Answers1

3

You want to create an object, so what you're looking for falls under the umbrella of creational design patterns. I'm not sure if there's a perfect fit for your needs, but the Factory pattern matches some of your needs.

In a typical Factory pattern use case, you would supply a type (as a String or enumeration) to a method, and receive a matching object. Your logic would be a little more complex in that there will be several inputs and some branching logic to locate the correct type. For example, you can't just use a String "shirt" to get your object since the color is built into the types (you have RedShirt, BlueShirt, etc...).

As a final note, I'd consider asking yourself why RedShirt and BlueShirt have to be of different types. Rather than using a design pattern to get around the issue, I'd reconsider the original design. For example, you could use an Apparel extends Product class containing a color and type member, such that you can query that information regardless of the type of Apparel. Of course, use your best judgement depending on your situation.

mlaota
  • 101
  • 6
  • 2
    Please note the linked tutorial describes a "Simple Factory". It is _not_ one of the Gang of Four design patterns. See: https://stackoverflow.com/a/50786084/1371329. – jaco0646 Jun 22 '20 at 13:21