Closed jnormen closed 1 month ago
Hi @jnormen, thank you for your question. To me the method HaveAnyAttributes(...)
works exactly as one would expect - the condition is fulfilled if any of the attributes is present for your class, interface, etc. You can find the implementation at the following line: https://github.com/TNG/ArchUnitNET/blob/fabf95b02eba6fa2b7dc2b75549662b8d12a4706/ArchUnitNET/Fluent/Syntax/Elements/ObjectConditionsDefinition.cs#L1095
You can also check the following simple Xunit example. The first test passes since the classes all have at least one of the attributes Test1
and Test2
. The attribute Test3
is not used anywhere and therefore simply ignored. The second test fails since the classes in question have neither of the three attributes:
[Fact]
public void HaveAnyAttributesPassingTest()
{
var classesWithAtLeastOneAttribute = Classes()
.That()
.Are(typeof(ClassWithAttribute1), typeof(ClassWithAttribute2), typeof(ClassWithBothAttributes))
.Should()
.HaveAnyAttributes(typeof(Test1), typeof(Test2), typeof(Test3));
classesWithAtLeastOneAttribute.Check(Architecture);
}
[Fact]
public void HaveAnyAttributesFailingTest()
{
var classesWithoutOneOfTheAttributes = Classes()
.That()
.Are(typeof(ClassWithoutAttributes), typeof(ClassWithDifferentAttribute))
.Should()
.HaveAnyAttributes(typeof(Test1), typeof(Test2), typeof(Test3));
classesWithoutOneOfTheAttributes.Check(Architecture);
}
[Test1]
internal class ClassWithAttribute1 { }
[Test2]
[Test4]
internal class ClassWithAttribute2 { }
[Test1]
[Test2]
internal class ClassWithBothAttributes { }
internal class ClassWithoutAttributes { }
[Test4]
internal class ClassWithDifferentAttribute{ }
internal class Test1 : Attribute { }
internal class Test2 : Attribute { }
internal class Test3 : Attribute { }
internal class Test4 : Attribute { }
If you still observe unexpected behavior with the method feel free to add a minimal example to your question.
[Fact]
public void Interfaces_Using_Refit_Should_End_With_Api()
{
Interfaces()
.That()
.HaveAnyAttributes(typeof(GetAttribute))
.Should()
.HaveNameEndingWith("Client")
.Because("All interfaces with Refit attributes should end with 'Api'")
.Check(Architecture);
}
GetAttribute is a Refit Atribute. When I do like this the test expect there shall be an Interface using this attribute. If I add that I want any of the get, post, put attributes then it force me to have all 3 in my code.
So if I do:
.HaveAnyAttributes(typeof(GetAttribute),typeof(PostAttribute))
And I have a GetAttribut no Post it complains there is no Post. And if I have a Post but no Get it says the opposite. So for me I'm forced to have all the attributes not just one of them.
for example:
public interface ISvsClient
{
[Post("/v1/balance-inquiry")]
public Task<BalanceEnquiryResponse> GetBalanceEnquiryAsync(SvsBalanceEnquiryRequest svsBalanceEnquiryRequest);
}
[Fact]
public void Interfaces_Using_Refit_Should_End_With_Api()
{
Interfaces()
.That()
.HaveAnyAttributes(typeof(GetAttribute),typeof(PostAttribute))
.Should()
.HaveNameEndingWith("Client")
.Because("All interfaces with Refit attributes should end with 'Api'")
.Check(Architecture);
}
ArchUnitNET.Domain.Exceptions.TypeDoesNotExistInArchitecture: Type Refit.GetAttribute does not exist in provided architecture or is no attribute.
When I wrote the issue I did not check the source code, and now when I answer I haven't checked the source code either, but I see that I use Interface() not classes and are not sure if the implementation is different. I'm on the move now so just wanted to add a fast example as is.
I did not use the .Are(typeof(ClassWithAttribute1), typeof(ClassWithAttribute2), typeof(ClassWithBothAttributes)) things. maybe that something I need to add?
When I do:
HaveAnyAttributes(....)
It always require me to have the first attribute set. but when I also add a list of other attributes it force me to have them as well..HaveAnyAttributes(typeof(GetAttribute), typeof(PostAttribute), typeof(PutAttribute), typeof(DeleteAttribute))