I am studying Cucumber in The Cucumber for Java Book, but there is an argument for the object to be injected in PicoContainer. I didn't write how to generate it with the constructor of, so I looked it up. (Actually, the latest Active JDBC (1.4.13) didn't work with the book sample (it worked with the same version of 1.4.1 as the book), so I needed an alternative.)
This is a partial modification of the sample in the above book, but I want to DI the Account object with cumcumber-picocontainer in Step Definition, but I need to specify the argument in the constructor when creating the Account object.
Account.java
public class Account extends Model {
public Account() {
}
public Account(int number) {
setInteger("number", number);
setString("balance", "0.00");
saveIt();
}
...
AccountSteps.java
public class AccountSteps {
private Account account;
public AccountSteps(Account account) {
this.account = account;
}
...
In the book, the same thing is achieved by creating a child class and DI it as shown below, instead of using the constructor with arguments directly.
TestAccount.java
public class TestAccount extends Account {
public TestAccount() {
super(1234);
}
...
AccountSteps.java
public class AccountSteps {
private TestAccount account;
public AccountSteps(TestAccount account) {
this.account = account;
}
...
How can I directly DI the Account object created by the constructor with arguments without doing that?
If you use PicoContainer directly instead of from Cucumber, you can create the object you want to DI yourself, or you can set it to create the object using a constructor with arguments.
MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(new Account(5)); //Create Account object in constructor with arguments
//Alternatively, specify the argument of the constructor
pico.addComponent(Account.class, Account.class, new Parameter[] { new ConstantParameter(new Integer(5)) });
Account account = pico.getComponent(Account.class);
System.out.println("number = " + account.getNumber());
When executed from Cucumber, MutablePicoContainer is generated by Cucumber and also sets the components to DI, so it is easy for the normal user to do nothing, but on the contrary I want to set it myself In that case, there is no way to get the MutablePicoContainer from Cucumber, so nothing can be done.
There was of course a similar request (Ability to configure PicoContainer), and the ObjectFactory API became available in response. But what you can do with this API is
pico.addComponent(Account.class)
(Although this makes sense because it allows you to specify which implementation class to use for Interface).
pico.addComponent(new Account(5));
pico.addComponent(Account.class, Account.class, new Parameter[] { new ConstantParameter(new Integer(5)) });
It seems that it is not possible at present to register an instance or specify an argument of the constructor like.
In fact, if the argument is a regular class instead of an int as in this example, you can do it normally. As a DI beginner, it took me a while to notice this. Since cucumber-picocontainer is clever, it will DI the object of the constructor argument without saying anything. So, it's a bit dirty implementation, but if you create a class (AccountNumber) for the argument of the constructor, you can do what you want.
Account.java
public class Account extends Model {
public Account() {
}
public Account(int number) {
setInteger("number", number);
setString("balance", "0.00");
saveIt();
}
//Constructor for DI
public Account(AccountNumber number) {
this(number.getNumber());
}
...
AccountNumber.java
public class AccountNumber {
private int number;
public AccountNumber() {
number = 1234;
}
public int getNumber() {
return number;
}
}
You can now pass the Account object you created with the arguments without changing anything in the Step Definition.
AccountSteps.java
public class AccountSteps {
private Account account;
public AccountSteps(Account account) {
this.account = account;
}
...
Recommended Posts