How can I enforce using Archunit that every class has a correspondent test class?
I'm able to get all the class that I want to check using this Rule:
classes().that()
.areNotInterfaces()
.and()
.areNotAnonymousClasses()
.and()
.areNotRecords()
.and()
.areNotEnums()
.should()
But not sure where to go from here.
Thanks
You can implement a "non-local" ArchCondition (i.e. one that relies on all objects to test) by overwriting its init(Collection<T> allObjectsToTest) method.
ArchUnit's library of GeneralCodingRules has a testClassesShouldResideInTheSamePackageAsImplementation(), whose implementation is a good starting point to come up with something like this:
#ArchTest
static final ArchRule relevant_classes_should_have_tests =
classes()
.that()
.areTopLevelClasses()
.and().areNotInterfaces()
.and().areNotRecords()
.and().areNotEnums()
.should(haveACorrespondingClassEndingWith("Test"));
private static ArchCondition<JavaClass> haveACorrespondingClassEndingWith(String testClassSuffix) {
return new ArchCondition<JavaClass>("have a corresponding class with suffix " + testClassSuffix) {
Set<String> testedClasseNames = emptySet();
#Override
public void init(Collection<JavaClass> allClasses) {
testedClasseNames = allClasses.stream()
.map(JavaClass::getName)
.filter(className -> className.endsWith(testClassSuffix))
.map(className -> className.substring(0, className.length() - testClassSuffix.length()))
.collect(toSet());
}
#Override
public void check(JavaClass clazz, ConditionEvents events) {
if (!clazz.getName().endsWith(testClassSuffix)) {
boolean satisfied = testedClasseNames.contains(clazz.getName());
String message = createMessage(clazz, "has " + (satisfied ? "a" : "no") + " corresponding test class");
events.add(new SimpleConditionEvent(clazz, satisfied, message));
}
}
};
}
Related
i have an issue on verifying a call to method of class under test, using the verify() method it tells that the call is not done to that method, this method is defined as abstract in super class (loadFile(String))
find bellow the code :
public abstract class FileParser {
public Iterator<String> loadFile(FileSettingsToSend fileSetting) {
System.out.println("file before staged");
try {
if(!movFile("staged",fileSetting))
return null;
System.out.println("file after move "+fileSetting.getFile().getAbsolutePath());
boolean isValidFormatFile = fileValidator.checkFileFormat(fileSetting);
if (!isValidFormatFile) {
System.out.println("file format is not valid");
return null;
}
return readBlock(fileSetting);
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
} finally {
}
//return null;
}
public abstract Iterator<String> readBlock(FileSettingsToSend fileSettingsToSend)
throws JsonProcessingException, IOException;
}
public class JsonFileParser extends FileParser {
public final ObjectMapper mapper = new ObjectMapper();
#Autowired
public JsonFileParser(FileValidator jsonFileValidatorService, FileAttributeService fileAttributeService) {
super(jsonFileValidatorService, fileAttributeService);
}
#Override
public Iterator<String> readBlock(FileSettingsToSend fileSetting) throws JsonProcessingException, IOException {
ObjectMapper mapper = new ObjectMapper();
System.out.println("inside readBlock json implementation");
List<String> listAttribute = fileAttributeService.getAttributes(fileSetting.getDiretoryPath());
String[] blocDelimitor = fileAttributeService.getDelimitorRepositpry(fileSetting.getDiretoryPath());
System.out.println("after validator");
final JsonNode root = mapper.readTree(fileSetting.getFile());
if (root == null)
return null;
Iterator<JsonNode> nodeIterator = root.elements();
System.out.println("Data is " + root);
return new Iterator<String>() {
JsonNode node;
#Override
public boolean hasNext() {
return nodeIterator.hasNext();
}
#Override
public String next() {
int i = 0;
node = nodeIterator.next();
System.out.println("after nex " + node.toString());
Arrays.stream(blocDelimitor).forEach(e -> {
node = node.path(e);
System.out.println("inside next " + node.toString());
});
String result = null;
if (node.isArray()) {
System.out.println("It is Array");
for (JsonNode node1 : node) {
if (i != 0)
result = result + "," + listAttribute.stream().map(e -> e + "=" + node1.get(e))
.collect(Collectors.joining(","));
else
result = listAttribute.stream().map(e -> e + "=" + node1.get(e))
.collect(Collectors.joining(","));
i++;
}
} else
result = listAttribute.stream().map(e -> e + "=" + node.get(e)).collect(Collectors.joining(","));
return result;
}
};
}
Test method is :
#Mock
FileValidator jsonFileValidatorService;
#Mock
FileAttributeService fileAttributeService;
JsonFileParser jsonFileParserMock = new JsonFileParser(jsonFileValidatorService, fileAttributeService);
#Test
public void validatorNotTrue() throws JsonProcessingException, IOException{
when(jsonFileValidatorService.checkFileFormat( anyObject() )).thenReturn(true);
JsonFileParser jsonFileParser = Mockito.spy(jsonFileParserMock);
doReturn(true).when(jsonFileParser).movFile(anyString(),anyObject() );
assertNull(jsonFileParser.loadFile(null));
verify(jsonFileParser, times(1)).movFile(anyString(),anyObject());
assertTrue(jsonFileParser.movFile(anyString(), anyObject()));
assertTrue(jsonFileValidatorService.checkFileFormat( anyObject() ));
//exception.expect(Exception.class);
verify(jsonFileParser,times(1)).readBlock(anyObject();
}
#BeforeClass
public static void settingUp(){
}
#Before
public void initMock(){
MockitoAnnotations.initMocks(this);
}
the line verify(jsonFileParser,times(1)).readBlock(anyObject(); return false; meaning that the method loadFile of jsonfileParser not called
can you get your held to tell why it is not called.
Thank you.
This happens because you initialize the mocks after you create a JsonFileParser. Note that #Before method is executed after all the fields of your test class are initialized.
As a result, you pass null dependencies to the class. The invocation to the null FileValidator throws NullPointerException, but you swallow it in your catch block.
Generally it is advisable to verify the arguments you pass to your constructors and methods, to fail fast in case of an error. For example, Java comes with a handy Objects::requireNonNull method to verify that the passed parameters are non-null.
Similarly it's generally a bad practice to swallow every single exception. For instance, in your example, you expect IOException and JsonProcessingException to be thrown. It's better to catch these explicitly and let the program crash (or at least log a warning) for any other one.
Finally, mocks and spies are prone to overuse. Usually, it's enough to use fakes - dummy implementations of your interfaces. Depending on how much control you have over the code, you may also want to refactor it to avoid using a spy at all. Using one in a code you may freely change may signal an architectural problem.
Following is my class
public final class Test {
enum Animal {DOG,CAT};
enum COLOR {RED,YELLOW};
class Meaningless {
String animal,color;
}
public void filter(List<Meaningless> meaninglesses){
meaninglesses.stream()
.filter(meaningless -> {
try {
Animal.valueOf(meaningless.animal);
return true;
}catch(Exception e){
return false;
}
})
.filter(meaningless -> {
try {
COLOR.valueOf(meaningless.color);
return true;
}catch(Exception e){
return false;
}
})
.collect(Collectors.toList());
}
}
The 2 iterations of filter methods essentially filters out the invalid enum types. How can I remove the code duplication from this ? The check should be generic enough so that I dont have to change the isValidEnum when there is a new enum introduced.
Ideally I would like to do something like
meaninglesses.stream()
.filter(meaningless -> isValidEnum(meaningless.animal,Animal.class))
.filter(meaningless -> isValidEnum(meaningless.color,COLOR.class))
The following utility method should do the trick here,
public static <E extends Enum<E>> boolean validateEnum(Class<E> clazz, String s) {
return EnumSet.allOf(clazz).stream().anyMatch(e -> e.name().equals(s));
}
And here's how your client code looks in practice,
boolean isValid = validateEnum(Animal.class, "DOG");
Finally, putting it back to your context, it should be something like this.
meaninglesses.stream()
.filter(meaningless -> validateEnum(Animal.class, meaningless.animal))
.filter(meaningless -> validateEnum(COLOR.class, meaningless.color))
.collect(Collectors.toList());
Instead of reinventing the wheel, you can simply go with Apache Common EnumUtils isValidEnum(Class<E> enumClass,String enumName)
Also, isValidEnumIgnoreCase(Class<E> enumClass,String enumName) can be used to check if you need case-insensitivity.
Docs here
I have two unrelated java classes (only *.class, no *.java) like this:
public class Trick {
public String getName() { return "Jack"; }
public String trick() { ... }
}
and
public class Treat {
public String getName() { return "John"; }
public String treat() { ... }
}
and I would like to generate a sort of Proxy class at runtime that represents the union of both classes and forwards them to the respective instance, and maybe throw if that's not possible. I assume that can be done with cglib but I don't know where to start.
This is what I would like to do (pseudocode):
// prepare: generate a common interface
TrickOrTreat trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
// use with concrete interface A:
Trick trick = new Trick();
TrickOrTreat proxyA = magic.createProxy(trickOrTreat.class, trick);
System.out.println("trick name: " + proxyA.getName());
// use with concrete interface B:
Treat treat = new Treat();
TrickOrTreat proxyB = magic.createProxy(trickOrTreat.class, treat);
System.out.println("treat name: " + proxyB.getName());
Or something to that effect. I would like to do it completely dynamically, probably cglib-based? If thats not possible I would do it with a code generation step in between?
If you are willing to trade in cglib, you can do this with Byte Buddy. I typically refuse to call it magic but here you go:
class Magic {
Class<?> createUnionInterface(Class<?> a, Class<?> b) {
DynamicType.Builder<?> builder = new ByteBuddy().makeInterface();
Set<MethodDescription.SignatureToken> tokens = new HashSet<>();
for (MethodDescription m : new TypeDescription.ForLoadedType(a)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
tokens.add(m.asSignatureToken());
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
for (MethodDescription m : new TypeDescription.ForLoadedType(b)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
if (!tokens.contains(m.asSignatureToken())) {
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
}
return builder.make()
.load(Magic.class.getClassLoader())
.getLoaded();
}
Object createProxy(Class<?> m, final Object delegate) throws Exception {
return new ByteBuddy()
.subclass(m)
.method(new ElementMatcher<MethodDescription>() {
#Override
public boolean matches(MethodDescription target) {
for (Method method : delegate.getClass()
.getDeclaredMethods()) {
if (new MethodDescription.ForLoadedMethod(method)
.asSignatureToken()
.equals(target.asSignatureToken())) {
return true;
}
}
return false;
}
}).intercept(MethodDelegation.to(delegate))
.make()
.load(Magic.class.getClassLoader())
.getLoaded()
.newInstance();
}
}
Note that you cannot reference a runtime-generated type at compile-time. This is however a given constraint with runtime code generation.
Magic magic = new Magic();
Class<?> trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
Trick trick = new Trick();
Object proxyA = magic.createProxy(trickOrTreat, trick);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyA));
Treat treat = new Treat();
Object proxyB = magic.createProxy(trickOrTreat, treat);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyB));
You can overcome this by generating your TrickOrTreat class prior to runtime such that you can reference the type at runtime.
As for the suggested union-type approach, this would require you to have at least one class to be an interface type as Java does not support multiple inheritance.
If you need functionality of both classes/interfaces you can use
public <TT extends Trick & Treat> void process(TT thing){
//...
}
edit:
Implement new Interface MyProxyHandler
public interface MyProxyHandler {}
Extend it with interfaces of classes say TreatInterface and TrickInterface
Create class ProxyManager that implements java.lang.reflect.InvocationHandler
public abstract class ProxyManager<T extends MyProxyHandler> implements InvocationHandler {
protected static String LOCK_OBJECT = new String("LOCK");
protected T proxyHandler;
protected List<T> handlers = new ArrayList<>();
#SuppressWarnings("unchecked")
public ProxyManager(Class<T> _clazz) {
proxyHandler = (T) Proxy.newProxyInstance(_clazz.getClassLoader(), new Class[]{_clazz}, this);
}
public T getProxy() {
return proxyHandler;
}
public List<T> getHandlers() {
return handlers;
}
public void setHandlers(List<T> handlers) {
this.handlers = handlers;
}
public boolean registerHandler(T handler) {
synchronized (LOCK_OBJECT) {
boolean add = true;
for (T item : this.handlers) {
if (item.getClass().equals(handler.getClass())) {
add = false;
}
}
if (add)
this.handlers.add(handler);
return add;
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String result = "";
for (MyProxyHandler handler : getHandlers()) {
try {
//I recommend that methods returns some enum like HANDLED/NOTHANDLED
result = (String) method.invoke(handler, args);
if (result.equals("Some flag"))
break;
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
return result;
}
}
Extend that class with your concrete class
public class TreatTrickProxyManager<T extends TreatInterface & TreatInterface> extends ProxyManager<T> {
public TreatTrickProxyManager(Class<T> _clazz) {
super(_clazz);
}
}
In your bussines logic class get an instance of TreatTrickProxyManager
In your method
public void retrieveSomeData(){
((TreatTrickProxyManager)getTreatTrickProxyManager().getProxy()).someMethodInvocation()
}
I'm trying to use hamcrest matchers to match a list of objects against a list/array of their properties. For one property value this is not a problem, because I can do something like this:
assertThat(savedGroup.getMembers(),
containsInAnyOrder(hasProperty("name", is(NAMES[0]))));
For multiple property values I can use multiple hasProperty() calls
assertThat(savedGroup.getMembers(),
containsInAnyOrder(
hasProperty("name", is(NAMES[0])),
hasProperty("name", is(NAMES[1]))));
But is there a generic way to match against all values in the NAMES array?
The best way (IMO) to do this would be to combine the overloaded containsInAnyOrder Matcher along with a custom FeatureMatcher. Ultimately your code would look like this:
String[] expectedNames = new String[] { "John", "Bob", "Carol"};
assertThat(savedGroup.getMembers(), hasNames(expectedNames));
hasNames is implemented as follows:
private Matcher<Iterable<? extends Member>> hasNames(String[] expectedNames) {
return containsInAnyOrder(Arrays.stream(expectedNames).map(name -> name(name)).collect(Collectors.toList()));
}
And the final part is the call to name which generates a Matcher that will extract a property in a type-safe way from your object:
private Matcher<Member> name(String name) {
return new FeatureMatcher<Member, String>(equalTo(name), "name", "name") {
#Override
protected String featureValueOf(Member actual) {
return actual.getName();
}
};
}
The benefit of doing it this is way is that:
You get the benefit of type-safety instead of using hasProperty
Your test now describes what you actual want to match on, i.e. hasNames
The code produced is now more flexible and composable. Want to match a single objects name? All you now need to do is assertThat(member, has(name("Fred")))
You can get even more composability by moving the equalTo sub-matcher to be part of the hasNames call like this:
private Matcher<Iterable<? extends Member>> hasNames(String[] expectedNames) {
return containsInAnyOrder(Arrays.stream(expectedNames).map(name -> name(equalTo(name))).collect(Collectors.toList()));
}
private Matcher<Member> name(Matcher<String> nameMatcher) {
return new FeatureMatcher<Member, String>(nameMatcher, "name", "name") {
#Override
protected String featureValueOf(Member actual) {
return actual.getName();
}
};
}
One of containsInAnyOrder's overloads accepts a collection of matchers as its argument. Thus you could do something like this:
assertThat(
savedGroup.getMembers(),
containsInAnyOrder(
Stream.of(NAMES)
.map(name -> hasProperty("name", is(name)))
.collect(Collectors.toList())
));
(if using Java 8, otherwise would need to add a loop building up the collection)
Need to make some cleanup (description output), but I think it does solve your problem:
package org.example.matchers;
import java.util.List;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeMatcher;
public class ContainsArrayElementsInAnyOrder<T> extends TypeSafeMatcher<List<T>> {
private T[] toMatch;
public ContainsArrayElementsInAnyOrder(final T[] toMatch) {
this.toMatch = toMatch;
}
#Override
protected boolean matchesSafely(List<T> item) {
if(item.size() != toMatch.length) {
return false;
}
for (T t : toMatch) {
if(!item.contains(t)) {
return false;
}
}
return true;
}
#Override
public void describeMismatchSafely(List<T> item, Description mismatchDescription) {
mismatchDescription.appendValueList("[", ",", "]", item);
}
#Override
public void describeTo(Description description) {
description.appendValueList("[", ",", "]", toMatch);
}
#Factory
public static <T> ContainsArrayElementsInAnyOrder<T> containsArrayElementsInAnyOrder(T[] elements) {
return new ContainsArrayElementsInAnyOrder<T>(elements);
}
}
Test:
#Test
public void shouldContainsInAnyOrderSameElementsInArrayAsInList() {
final String[] NAME = new String[]{"name3", "name1", "name2"};
final List<String> result = new ArrayList<>(3);
result.add("name2");
result.add("name1");
result.add("name4");
assertThat(result, containsArrayElementsInAnyOrder(NAME));
}
Output if not match:
java.lang.AssertionError:
Expected: ["name3","name1","name2"]
but: ["name2","name1","name4"]
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)
at ..
I'm attempting to make a system similar to https://github.com/ElgarL/TownyChat/blob/master/src/com/palmergames/bukkit/TownyChat/TownyChatFormatter.java
replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
#Override
public String call(String match, LocalTownyChatEvent event) throws Exception {
return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
}
});
replacer.registerFormatReplacement(Pattern.quote("{town}"), new TownyChatReplacerCallable() {
#Override
public String call(String match, LocalTownyChatEvent event) throws Exception {
return event.getResident().hasTown() ? event.getResident().getTown().getName() : "";
}
});
and more.
Is there a way to use annotations to cut down on the amount of repeated code, avoiding reflection to call the call method, and only using it during registration, if at all?
I'm not adverse to the idea of creating an annotation pre processor as I was already planning on doing this to enable automatically generating documentation.
Let's assume you write a small Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
#interface PatternHandler {
String value();
}
And create a class like
class Callables {
#PatternHandler("foo")
public static final TownyChatReplacerCallable FOO = new TownyChatReplacerCallable() {
#Override
public String call(String match, String event) {
return "This is foo handler called with " + match + "," + event;
}
};
#PatternHandler("bar")
public static final TownyChatReplacerCallable BAR = new TownyChatReplacerCallable() {
#Override
public String call(String match, String event) {
return "This is foo handler called with " + match + "," + event;
}
};
}
Now you can take the whole class or even multiple classes that contain those static fields and pass it to some registry method that iterates reflectively over each field in that class and if it's an annotated callable registers that.
class AnnotationRegistry {
public static void register(String pattern, TownyChatReplacerCallable handler) {}
public static void register(Class<?> clazz) {
// only fields declared by this class, not inherited ones (static fields can't be inherited)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// must have that annotation
PatternHandler annotation = field.getAnnotation(PatternHandler.class);
if (annotation != null) {
// must be static
if (!Modifier.isStatic(field.getModifiers())) {
System.out.println("Field must be static:" + field.getName());
continue;
}
// get content of that field
try {
Object object = field.get(null);
// must be != null and a callable
if (object instanceof TownyChatReplacerCallable) {
register(annotation.value(), (TownyChatReplacerCallable) object);
} else {
System.out.println("Field must be instanceof TownyChatReplacerCallable:" + field.getName());
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
That would save you a bit code and would have no speed disadvantage at runtime since there is no need to use reflection to call those callables.
Full example here: http://ideone.com/m3PPcY
Besides using static fields, you can also use non static ones if you pass an instance of a class to the registry which would then be used like Object object = field.get(instance); instead of the null.
Furthermore, instead of fields the same approach would work with methods which would be less code to write:
#PatternHandler("foo")
public static String fooMethod(String match, String event) {
return "This is foo handler called with " + match + "," + event;
}
Registry would then look for all Methods. Then for example wrap them in
class MethodAdapter implements TownyChatReplacerCallable {
private final Method method;
public MethodAdapter(Method m) {
method = m;
}
#Override
public String call(String match, String event) {
try {
return (String) method.invoke(null, match, event);
} catch (Exception e) {
e.printStackTrace();
return "OMGZ";
}
}
}
and continue as usual. But beware: invoking a method reflectively is potentially slower than calling it directly via code - few percent only, nothing to worry about
Full example for methods: http://ideone.com/lMJsrl
You can try new Java 8 Lambda Expressions instead (http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html).
replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
#Override
public String call(String match, LocalTownyChatEvent event) throws Exception {
return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
}
});
Can be written as :
replacer.registerFormatReplacement(
Pattern.quote("{worldname}"),
(match, event) -> { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); }
});
You can also push it further with another interface, method, ... that wrap it