I want to test the addMCU
and removeMCU
methods of my MCUModel
class using Spock. However, I am a bit puzzled on how to approach this.
public class MCUModel {
private static int counter = 1;
private final ObjectProperty<MCU> selectedMCU;
private final ObservableList<MCU> mcuList;
public MCUModel() {
selectedMCU = new SimpleObjectProperty<>(null);
mcuList = FXCollections.observableArrayList();
}
public ObjectProperty<MCU> selectedMCUProperty() {
return selectedMCU;
}
public void setSelectedMCU(MCU mcu) {
selectedMCU.set(mcu);
}
public ObservableList<MCU> getMCUList() {
return mcuList;
}
public void addMCU() {
MCU mcu = new MCU();
mcu.setName("MCU" + counter++);
mcuList.add(mcu);
selectedMCU.set(mcu);
}
public void removeMCU() {
if (selectedMCU.get() == null) return;
int index = mcuList.indexOf(selectedMCU.get());
mcuList.remove(index);
if (mcuList.size() == 0)
selectedMCU.set(null);
else if (mcuList.size() > index)
selectedMCU.set(mcuList.get(index));
else
selectedMCU.set(mcuList.get(--index));
}
}
In other examples on here the suggestion was made to change the constructor along the lines of:
public MCUModel(ObjectProperty<MCU> selectedMCU, ObservableList<MCU> mcuList) {
this.selectedMCU = selectedMCU;
this.mcuList = mcuList;
}
This would allow me to mock the fields in order to test whether there methods are called or not. However, I am not sure that this is the right approach in this particular case.
I would guess that, in case of the addMCU
method, that I want to test whether or not an new instance is created, and that both mcuList.add(mcu)
and selectedMCU.set()
are called and passed this instance.
Your instincts are correct and you do not need to mock the fields of the MCUModel
in order to test it. Doing so would couple your tests to implementation details of the class's private data. Tests needn't know that MCUModel
has any fields or dependencies at all; and keeping the tests ignorant of dependencies allows you the freedom to change them in the future (i.e. refactor) without breaking the tests.
I would test the setters through the getters. You might break this up into more than two tests or perhaps use a loop; but the idea is to test each method with the model in at least two states: empty and populated.
def "AddMCU"() {
given: "Empty model"
MCUModel model = new MCUModel()
when: "Add to empty model"
model.addMCU()
then: "Model is populated"
model.getMCUList().size() == 1
model.selectedMCUProperty() == model.getMCUList().first()
when: "Add to populated model"
model.addMCU()
then: "Model size increments"
model.getMCUList().size() == 2
model.selectedMCUProperty() == model.getMCUList().last()
}
def "RemoveMCU"() {
given: "Populated model"
MCUModel model = new MCUModel()
model.addMCU()
when: "Remove from populated model"
model.removeMCU()
then: "Model is empty"
model.getMCUList().isEmpty()
model.selectedMCUProperty() == null
when: "Remove from empty model"
model.removeMCU()
then: "Model remains empty"
model.getMCUList().isEmpty()
model.selectedMCUProperty() == null
}