Felix Grund
Instructor @ UBC
@BeforeEach
public void setup() {
this.bird = new Eagle();
}
@Test
public void testBirdFlies() {
// THIS TEST SHOULD PASS
// REGARDLESS OF THE ACTUAL TYPE
assertTrue(this.bird.fly());
}
Bird.fly()
Eagle.fly()
bird.fly()
eagle.fly()
no change
no change
wider
narrower
narrower
wider
Preconditions
Postconditions
Barbara Liskov
Superclass
Subclass
// REQUIRES: input >= 0
// EFFECTS: sets the input
public void setInput(int input) {
this.input = input;
}
// REQUIRES: input >= 100
// EFFECTS: sets the input
@Override
public void setInput(int input) {
super.setInput(input);
}
Y
N
Y
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
Superclass
Subclass
// REQUIRES: input >= 0
// EFFECTS: sets the input
public void setInput(int input) {
this.input = input;
}
// REQUIRES: input >= -100
// EFFECTS: sets the input
@Override
public void setInput(int input) {
super.setInput(input);
}
N
N
N
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
Superclass
Subclass
// EFFECTS: returns an integer
// in the range [0, 100)
public int produceValue() {
return input % 100;
}
// EFFECTS: returns an integer
// in the range [0, 200)
@Override
public int produceValue() {
return input % 200;
}
Y
N
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
Y
Superclass
Subclass
// EFFECTS: returns an integer
// in the range [0, 100)
public int produceValue() {
return input % 100;
}
// EFFECTS: returns an integer
// in the range [0, 50)
@Override
public int produceValue() {
return input % 50;
}
N
N
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
N
public class Square extends Rectangle {
@Override
public int setDimensionsReturnSurfaceArea(int height, int width) {
if (height != width) {
throw new RuntimeException("For a Square implementation height must match width");
}
return super.setDimensionsReturnSurfaceArea(height, width);
}
}
public class Rectangle {
protected int height;
protected int width;
public int setDimensionsReturnSurfaceArea(int height, int width) {
this.height = height;
this.width = width;
return height * width;
}
}
Valid inputs become more limited with subtype!
public class ShapeTest {
private Rectangle rectangle;
@BeforeEach
public void setup() {
this.rectangle = new Square();
}
@Test
public void testSetDimensionsReturnSurfaceArea() {
// THIS WILL THROW AN EXCEPTION!
int surfaceArea = this.rectangle.setDimensionsReturnSurfaceArea(10, 20);
assertEquals(200, surfaceArea);
}
}
Test based on the super type does not pass on the subtype!
List<String> list = Arrays.asList("One", "Two");
list.remove("One");
https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList-T...-
https://stackoverflow.com/questions/1624144/unsupportedoperationexception-when-trying-to-remove-from-the-list-returned-by-ar
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
Superclass
Subclass
// REQUIRES: a sorted tree
// EFFECTS: returns true if the element is
// in the tree, returns false otherwise
// REQUIRES: any tree
// EFFECTS: returns true if the element is
// in the tree, returns false otherwise
N
N
N
Superclass
Subclass
// REQUIRES: any tree
// EFFECTS: returns true if the element is
// in the tree, returns false otherwise
// REQUIRES: a sorted tree
// EFFECTS: returns true if the element is
// in the tree, returns false otherwise
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
Y
N
Y
Superclass
Subclass
// REQUIRES: a sorted tree
// EFFECTS: returns 1 if the element is
// in the tree, returns 0 otherwise
// REQUIRES: a sorted tree
// EFFECTS: if the element is in the
// tree, returns the number of elements
// in the tree that are larger,
// otherwise returns 0
Is precondition narrower?
Is postcondition wider?
Is LSP violated?
A
B
C
N
Y
Y
By Felix Grund