Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require positive results by default #201

Merged
merged 3 commits into from
Oct 13, 2023

Conversation

simonthum
Copy link
Contributor

This is a breaking change that requires rules to yield positive results by default. The intent is to protect against misformulated rules.

This is the first public iteration. It still loses type information on WithoutRequiringPositiveResults(), but otherwise I think it's fine.

Resolves #189

@simonthum
Copy link
Contributor Author

simonthum commented Dec 19, 2022

The new code properly highlights the fact that the example tests do not test anything:

[xUnit.net 00:00:02.13]     ExampleTest.ExampleArchUnitTest.ExampleClassesShouldNotCallForbiddenMethods [FAIL]
  Failed ExampleTest.ExampleArchUnitTest.ExampleLayerShouldNotAccessForbiddenLayer [566 ms]
  Error Message:
   ArchUnitNET.xUnit.FailedArchRuleException : "Types that are Example Layer should not depend on Forbidden Layer because it's forbidden" failed:
	The rule requires positive evaluation, not just absence of violations. Use WithoutRequiringPositiveResults() or improve your rule's predicates.

Although something needs to be done about it, I view this as an encouraging sign.

I'll include the signoffs.

@simonthum simonthum force-pushed the feature/strict-evaluation branch 2 times, most recently from 48553de to 59a20b3 Compare January 8, 2023 13:21
The change is intended to make it easier to detect ineffective rules,
as you can see in the example unit test. This change obviously breaks
some tests, so it can be defeated per rule with a call to

    .WithoutRequiringPositiveResults().

Should().Exist() and NotExist() rules automatically defeat the check
so their error messages should remain stable. However, the logic to check
for (non)exitence had to be modified which may cause inconvenience.

The implemetation basically treats an empty result set as a non-passing
result (i.e. a violation).

The change breaks a lot of unit tests, mostly those which iterate
over a bunch of test types and are tautologies. This issue is adressed
in a subsequent commit.

Signed-off-by: Simon Thum <[email protected]>
These tests fail with the new stricter evaluation logic. This commit
marks them with the WithoutRequiringPositiveResults() call to have them
run again.

However, in some cases this condition indicates that the test may not
be effective.

Signed-off-by: Simon Thum <[email protected]>
These tests did, for different reasons, not execute against test
types, so they fail now. There was not always a clear fix, so
I opted to skip them to preserve the intent and compile-time
correctness of these tests.

Signed-off-by: Simon Thum <[email protected]>
@simonthum simonthum force-pushed the feature/strict-evaluation branch from 59a20b3 to 428656b Compare January 8, 2023 13:31
@fgather
Copy link
Contributor

fgather commented Jan 8, 2023

Hey @simonthum ,
thanks for the PR, it looks really promising. @MSinstein , @fholger , what do you think?

@fholger
Copy link
Contributor

fholger commented Jan 23, 2023

Hey @simonthum , thanks for the PR, it looks really promising. @MSinstein , @fholger , what do you think?

Looks good to me, though it is a breaking change and would probably benefit from some beta-testing by other real-world users.

@simonthum
Copy link
Contributor Author

I agree with the concern. Is there an update site for CI results or qualified nuget builds available?

@fgather
Copy link
Contributor

fgather commented Jan 25, 2023

I will try to public some beta-release on nuget

@simonthum
Copy link
Contributor Author

Hey, is there any progress to be aware of?

@WietseDeKoninckPXL
Copy link

This is an absolutely required addition (in this form or another) in my opinion.

As a new user I was confused that rules still passed even though absolutely nothing was modeled in my architecture yet, which means

A) There were technically no violations
B) But also no reason that warrants the existence of the rule

So if a user writes a rule that doesn't apply to the architecture nor presents any violations, the rule does not test anything.

@fgather fgather merged commit 100914d into TNG:main Oct 13, 2023
@simonthum
Copy link
Contributor Author

Thanks for merging!

However, it probably makes sense for a maintainer to stop by and look at the loss of type information I mentioned.

@alexanderlinne alexanderlinne mentioned this pull request Apr 12, 2024
@sdepouw
Copy link

sdepouw commented Jan 1, 2025

Great addition, but this behavior needs documented beyond the release notes. The failure message does tell you how to manually bypass it (by adding WithoutRequiringPositiveResults()) but does not mention what a "positive result." As a completely new user to ArchUnit, I thought I wasn't doing an assertion correctly or something. Not that the class collection under test was empty.

@simonthum
Copy link
Contributor Author

Good point, I'll do something about it.

@simonthum
Copy link
Contributor Author

simonthum commented Jan 1, 2025

@sdepouw How does that sound:

$"The rule requires positive evaluation, not a mere absence of violations. Use {nameof(WithoutRequiringPositiveResults)}() or write your rule's predicates such that they evaluate to true on actually existing code."

Or from scratch:

"There seems to be no code this rule could test. Please check the rule's predicates or use WithoutRequiringPositiveResults() if that is intentional."

@sdepouw
Copy link

sdepouw commented Jan 2, 2025

@simonthum The in-code error could be the second one, although I'd probably clarify that "no code this rule could test" means that the predicate itself found no items.

And then somewhere in documentation for this specific error, it can be elaborated with stuff like this:

If your rule's predicate returns no results (e.g. IObjectProvider<Class> myPredicate = Classes().That().ImplementInterface("IDoNotExist").As("This Object Provider Will Be Empty")) then the rule is not evaluating against anything, hence the error.

You can verify your predicate's contents by writing int numberOfItems = _sorterClasses.GetObjects(Architecture).Count();

(Can be formatted nicer of course in documentation.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Architecture rule validation: expect passes
5 participants