How can you create a factory method to replace a constructor with functionality?

StackOverflow https://stackoverflow.com/questions/20645230

  •  19-09-2022
  •  | 
  •  

質問

I currently have a constructor that has some functionality inside. I know this can't be good. It makes it impossible to test the expected output of the method inside here. How can I change this up?

public loan(BigDecimal amount, BigDecimal interestRate, BigDecimal years) {

    this.amount = amount.multiply(BigDecimal.valueOf(100));
    this.interest = interestRate;
    this.initialTermMonths = years.multiply(BigDecimal.valueOf(12));

    this.monthlyPaymentAmount = calculateMonthlyPayment();
}

There is no way for me to make a JUnit test to assert the calculateMonthlyPayment() method output. How can I change this into a factory method? Or is there another way?

役に立ちましたか?

解決

You could simply provide a getter method for monthly payment:

public double getMonthlyPayment() {
    return this.monthlyPaymentAmount;
}

Then in your test, do the following:

  1. Instantiate the object, passing it certain values that should result in a known value for monthly payment.

  2. Call getMontlyPaymet()

  3. Compare the result of step 2 to the expected value in step 1.

It's debatable if logic is appropriate in the constructor. In your case, I believe it is. This logic, in the constructor, ensures that the object is always in a fully-initialized state. If you were to factor out this logic into a static method, and then target your test at that method, you would not be validating that the state of your objects will always be correct.

If you add the additional public static method, you are providing that as an interface to your class, which does not seem to be your intention. Making it public simply for the sake of testing is called a "testing scar". Do not allow your tests to compromise the design of your class.

他のヒント

The simplest way is to turn calculateMonthlyPayment() into a public static method, as

public static BigDecimal calculateMonthlyPayment(BigDecimal amount, 
        BigDecimal interestRate, BigDecimal years) {
    // calculate and return result
}

And call this inside your constructor. However from the example you posted I fail to see why do you need a class when a simple method could be enough.

If you need to assert calculateMonthlyPayment(), you can just do an assertion on the getter of monthlyPaymentAmount.

Generally speaking I'm not a big fun of business logic inside a constructor. Since I'm looking only at the constructor I would suggesto to go static and just passing those 3 parameters to a public static calculateMontlyPayment.

P.S: you should call your class Loan and not loan. Read about JavaBean conventions.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top