Question: Whether or not a value is `null` could be checked implicitly like this:

```
assertThat(value).isEqualTo("something");

```

Or it could be checked explicitly:

```
assertThat(value).isNotNull();
assertThat(value).isEqualTo("something");

```

The latter makes the expectations a bit more clear, but it blows up the test code.

Is there a good reason to prefer the second approach over the first?

Answer: 
If all your objects are immutable, there is no problem. Every Square is also a Rectangle. All the properties of a Rectangle are also properties of a Square.

The problem begins when you add the ability to modify the objects. Or really - when you start passing arguments to the object, not just reading property getters.

There are modifications that you can do to a Rectangle that maintain all the invariants of your Rectangle class, but not all Square invariants - like changing the width or height. Suddently the behavior of a Rectangle isn't just its properties, it is also its possible modifications. It's not just what you get out of the Rectangle, it's also *what you can put in*.

If your Rectangle has a method `setWidth` that is documented as changing the width and not modifying the height, then Square cannot have a compatible method. If you change the width and not the height, the result is no longer a valid Square. If you chose to modify both width and height of the Square when using `setWidth`, you are not implementing the specification of Rectangle's `setWidth`. You just can't win.

When you look at what you can "put into" a Rectangle and a Square, what messages you can send to them, you'll likely find that any message you can validly send to a Square, you can also send to a Rectangle.

It's a matter of co-variance vs. contra-variance. 

Methods of a proper subclass, one where instances can be used in all cases where the superclass is expected, requires each method to:

* Return only values that the superclass would return - that is, the return type must be a subtype of the superclass method's return type. Return is co-variant.
* Accept all values that the supertype would accept - that is, the argument types must be supertypes of the superclass method's argument types. Arguments are contra-variant.

So, back to Rectangle and Square: Whether Square can be a subclass of Rectangle depends entirely on which methods Rectangle have. 

If Rectangle has individual setters for width and height, Square won't make a good subclass.

Likewise, if you make some methods be co-variant in the arguments, like having `compareTo(Rectangle)` on Rectangle and `compareTo(Square)` on Square, you will have a problem using a Square as a Rectangle.

If you design your Square and Rectangle to be compatible, it will likely work, but they should be developed together, or I'll bet that it won't work.
Because by LSP, creating inheritance relation between the two and overriding `setWidth` and `setHeight` to ensure square has both as same introduces confusing and non-intuitive behavior. Lets say we have a code:

```php
Rectangle r = createRectangle(); // create rectangle or square here
r.setWidth(10);
r.setHeight(20);
print(r.getWidth()); // expect to print 10
print(r.getHeight()); // expect to print 20

```

But if the method `createRectangle` returned `Square`, because it is possible thanks to `Square` inheriting from `Rectange`. Then the expectations get broken. Here, with this code, we expect setting width or height will only cause change to width or height respectively. The point of OOP is that when you work with the superclass, you have zero knowledge of any subclass under it. And if subclass changes the behavior so that it goes against expectations we have about superclass, then there is high chance that bugs will occur. And those kind of bugs are both hard to debug and fix.

One of the major ideas about OOP is that it is behavior, not data that is inherited (which is also one of the major misconceptions IMO). And if you look at square and rectangle, they have no behavior themselves that we could relate in inheritance relation.