OAStackView icon indicating copy to clipboard operation
OAStackView copied to clipboard

Move to constraint based unit testing

Open nsomar opened this issue 9 years ago • 6 comments

Right now the unit test works by asserting the frames of the arranged views. Checking on the frame might be a brittle way to assert correctness. In order to be more sure about the correctness, it would be better to move to assert on the constraint that OAStackView generates instead.

In order to address this issue, all the code similar to:

layoutView(stackView);
[[theValue(CGRectGetMinX(view1.frame)) should] equal:theValue(0)];

Must be updated to check on stackView constraints and comparing them with the real UIStackView generated ones.

nsomar avatar Jun 24 '15 20:06 nsomar

Fully agree with this.

Additionally, how do you feel about trying to match the constraints generated by UIStackView itself ?

I've been poking around in a playground and inspecting the UIStackView generated constraints, and they're somewhat different.

It may be interesting to set up tests that:

  1. configure a UIStackView according to the settings under test
  2. configure a OAStackView with identical settings
  3. assert that the constraints match

bartvandendriessche avatar Jun 25 '15 12:06 bartvandendriessche

@bartvandendriessche comparing with UIStackView would be great! I'm not sure however if checking the constraints is the right level, because OAStackView might need different constraints e.g. for backward compatibility. The tests could also compare snapshots of identically set-up UIStackViews and OAStackViews.

Thomvis avatar Jun 25 '15 20:06 Thomvis

I think it would be good to have a mix of both of these unit tests. I noticed that having the same frame on different iOS versions might not be possible, as applying the same constraints on iOS7 and iOS8 results in different frames after the layout pass. I think a decision regarding frame vs constraint must be taken early since it will affect the way the project will be moving forward.

Do you guys have some arguments/opinion on wether OAStackView should favour constraint over frames or the opposite?

nsomar avatar Jun 27 '15 01:06 nsomar

Hmm, do you maybe have an example where the same constraints produce different results on iOS 7 and iOS 8 ?

I mean obviously iOS7 is lacking the baseline and margin oriented NSLayoutAttribute's but for the rest, it seems like constraints should lead to the same outcome.

bartvandendriessche avatar Jun 27 '15 11:06 bartvandendriessche

Another question; does it make sense to mimic NSLayoutGuides using invisible UIViews ?

Looking at the constraints generated by UIStackView, it is clear that the implementation leans heavily on the use of the new NSLayoutGuide class.

As mentioned in the "Mysteries of Auto Layout, part 2" WWDC talk (session 219), NSLayoutGuide doesn't allow anything new per se, it just does optimises something that used to be done with invisible UIViews.

It might be a good idea to build constraints against such invisible UIViews where UIStackView uses NSLayoutGuides.

In particular for the UIStackViewDistributionEqualCentering and UIStackViewDistributionEqualSpacing, I think we'll have to add invisible subviews anyway.

Some of the layout guides used by UIStackView are:

UIViewLayoutMarginsGuide

There is at most a single UIViewLayoutMarginsGuide.

This is basically the new layoutMarginsGuide and is used to create constraints of type "UI-canvas-connection" if layoutMarginsRelativeArrangement is true.

UI-alignment-spanner

There is always a single UI-alignment-spanner.

This layout guide is used to create constraints of type "UI-spanning-boundary".

The constraints are between the arrangedSubviews edges transverse to the axis (so Top and Bottom if axis is Horizontal, Leading and Trailing if Vertical).

These constraints are of priority UILayoutPriorityRequired, but they are lenient in that they use >= and <= relations.

UI-ordering-spanner

There is always a single UI-ordering-spanner.

Like the UI-alignment-spanner, this guide is used to create constraints of type "UI-spanning-boundary".

The constraints are made against the same edges as those from the UI-alignment-spanner.

These constraints are .5 less than UILayoutPriorityRequired, but they are strict in the sense that they use == relations.

UI-distributing

There can be 0 or n UI-distributing guides.

These guides are only used when distribution is UIStackViewDistributionEqualSpacing or UIStackViewDistributionEqualCentering.

They basically mimic empty views in between the arrangedSubviews.

These guides create constraints labeled "UI-distributing-edge". They constrain arrangedSubviews edges parallel to the axis to make sure the space in between the arrangedSubviews is equal.

If there are multiple UI-distributing guides, they will constrain themselves to have equal widths or heights depending on the axis (width for Horizontal, height for Vertical).

bartvandendriessche avatar Jun 27 '15 15:06 bartvandendriessche

It'd probably be useful, for performance, to make an OALayoutGuide class that's nothing more than a UIView backed with a CATransformLayer

harlanhaskins avatar Jun 27 '15 15:06 harlanhaskins