testing methods that accept Class arguments - java

I'm trying to figure out how test a small library I'm working on . Using this simplified method as an example:
private int countMappableFields(Class<?> type) {
int mappableFields = 0;
Field[] fields = type.getFields();
for (int i = 0; i < fields.length ; i++) {
if (FieldHelper.isMappable(fields[i]))
mappableFields++;
}
return mappableFields;
}
Should I define a couple of classes in separate files and reference them in all my tests? Is there a different approach that will allow to construct an object for each case?

You can define the classes inline in your test class; there's no reason to make separate files for them.
public class TestCase {
private static class NoFieldClass
{
}
// And so on.
#Test
public void shouldFindZeroMappableFieldsInNoFieldClass() {
assertTrue(0 == countMappableFields(NoFieldClass.class));
}
}
This keeps your test source code area clean. It will create multiple class files, but at least the inline classes you define will look like "TestCase$NoFieldClass.class" instead of being the top-level "NoFieldClass.class".

I'd typically just make a private static class inside the test class for that sort of thing. If you have multiple test files needing to do the same sort of thing, you might want to create top level classes instead.

Depends on what you're testing for. If you're doing some sort of customized reflection (e.g. FieldHelper is only returning a subset of fields for some reason) you might want to actually test the objects you're going to be using it on) - i.e. actually run your reflection tests on a map<CLass,Integer> where the classes are mapped to the expected values.

Related

How to append a method to existing class using annotation processing in java / kotlin?

I'm new to annotation processing and code generation. I want to find out how can I perform such operation like appending new method to existing class. Here is an example of what I want to do:
Assume that we have a class with with custom annotations like this one:
class SourceClass {
#CustomAnnotation
fun annotatedFun1(vararg argument: Any) {
//Do something
}
#CustomAnnotation
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
And the result I want to get - extended copy of that class:
class ResultClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
fun annotatedFun1(vararg argument: Any) {
//Do something
}
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
I've already found out how to create annotation processor. I'm looking for a method to save all existing fields, properties and methods in source class and to append a few more methods to it.
If it is possible to modify class without creating new one - it would be perfect, but in all tutorials only new classes are created and I didn't find any example where all contents of source class are being copied to another one.
Please, do not advise to use reflection. I need this for android and so reflection is not the option cause of resources cost. I'm looking for compile-time solution.
It is required for custom script language implemented in app and should be used to simplify wrapper classes structure. When this job is done directly in code - it looks awful when such method count exceeds 20 per class.
Here is a good example of Java Annotation Processing I recently worked with.
It's an implementation of #Immutable annotation.
Check out ByteBuddy or Kotlin Poet to understand how additional code generation works.
For Kotlin you do almost the same, check this manual for Kotlin-specific steps.
With Kotlin, you can use extension functions and that is the recommended way of adding new functionality to existing classes that you don't control. https://kotlinlang.org/docs/reference/extensions.html
You may be abel to follow the pattern used by Project Lombok. See How does lombok work? or the source code for details.
Another option would be to write a new class that extends your source class:
class ResultClass : SourceClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
}
Or perhaps use composition instead and implemnent cover methods for all the public methods in SourceClass.
If you are not tied to doing this using annotation processing, you could use a separate piece of custom code to process the source code files before compiling. Maybe use a regular expression like /#CustomAnnotation\s+.*fun (\w+)\s*\(([^)]*)\)/gm (Test on Regex101) to find the annotated methods.
If I understood the requirement correctly, the goal is to implement something like described below.
You have a source file C.java that defines the class C like this:
public final class C
{
#Getter
#Setter
private int m_IntValue;
#Getter
#Constructor
private final String m_Text;
}
And now you want to know how to write an annotation processor that jumps in during compilation and modifies the source from C.java that the compiler sees to something like this:
public final class C
{
private int m_IntValue;
public final int getIntValue() { return m_IntValue; }
public final void setIntValue( final int intValue ) { m_IntValue = intValue; }
private final String m_Text;
public final String getText() { return m_Text; }
public C( final String text ) { m_Text = text; }
}
The bad news is, that this is not possible … not with an annotation processor, not for Java 15.
For Java 8 there was a way, using some internal classes with reflection to convince the AP to manipulate the already loaded source code in some way and let the compiler compile it a second time. Unfortunately, it failed more often than it worked …
Currently, an annotation processor can only create a new (in the sense of additional) source file. So one solution could be to extend the class (of course, that would not work for the sample class C above, because the class itself is final and all the attributes are private …
So writing a pre-processor would be another solution; you do not have a file C.java on your hard drive, but one named C.myjava that will be used by that preprocessor to generate C.java, and that in turn is used by the compiler. But that is not done by an annotation processor, but it may be possible to abuse it in that way.
You can also play around with the byte code that was generated by the compiler and add the missing (or additional) functionality there. But that would be really far away from annotation processing …
As a summary: today (as of Java 15), an annotation processor does not allow the manipulation of existing source code (you cannot even exclude some source from being compiled); you can only generate additional source files with an annotation processor.

JUnit Call a test method in one class from another class

Had a quick look at past questions, couldn't see something similar so here goes:
I also made a mistake in choosing dummy names for this example to illustrate my point, I'll rename them.
I have a class which has a JUnit test:
public class CheckFilter {
#Test
public void Run_filter_test() {
//some code
}
}
And then another class:
public class CheckVideoPlays {
#Test
public void Play_video_in_full() {
//some more code here etc
}
}
Finally, how do I call these two tests from another class, obviously you can't extend multiple classes.
public class RunAllTests {
//How do i call both
//eg
//
//Run_filter_test();
//Play_video_in_full();
}
Note: I don't want to call the class. Don't want to run as:
#RunWith(Suite.class)
#Suite.SuiteClasses({
CheckFilter.class,
CheckVideoPlays.class
})
A few things.
Change the name of Sanatize_all_inputs to the (java standard form) camel case, perhaps sanitizeAllImports. When using Java, obey Java.
It seems likely that you will sanitize inputs once per test,
which, to me, indicates that you want a class level variable of type ConvertAll in your jUnit test class.
Either use composition (another class level variable of type BaseTestBlammy) or inheritance (extend class BaseTestBlammy) to acquire access to the BaseTestBlammy methods.
Here is an example:
public MyJunitTestKapow
extends BaseTestBlammy
{
private final ConvertAll convertAll;
public MyJunitTestKapow()
{
convertAll = new ConvertAll();
}
#Test
public void someTest()
{
convertAll.sanitizeAllInputs(...);
... // do the rest of the test here.
}
}
You could make static method in ConvertAll.sanitize then call this method in both ConvertAll.Sanitise_all_inputs test and CheckFilter.Run_filter_test
As better (more maintainable and powerful) solution you may create Sanitiser class with sanitise() method (method may be static or not). Then each class that requires sanitise functionality will call Sanitiser.sanitise. This soltion may be better in long run- you may pass paramethers to sanitise method (or to Sanitiser constructor), Sanitiser may have some internal state, etc
Side note: you may consider migrating to Junit5 (basically it is just change of imported packages). Junit5 has #DisplayName annotation that declares nice test method names (with spaces). So your test methods will respect Java naming convention.
#Test
#DiplayName("Sanitize all inputs")
public void sanitiseAllInputs() {
//some more code here etc
}

Suggestions for implementing a solution using Singleton design pattern

I need to implement a solution as part of Test framework & I am considering singleton pattern for reasons explained below. However, I am not able to achieve my intended solution & therefore would need some suggestions/inputs on possible implementations.
Problem Statement :
I have a environment (env of the product I am testing) configuration properties file which I want to load & make the value of the parameters accessible globally to the test framework.
I figured using the singleton pattern because these properties are one-time values (should report an exception if tried to initialize more than once), should be available globally & have an one-point access to the methods.
However, the list of properties/parameters is really long & therefore it's wise to break it into modules (classes). For the below explanation, I tried with composition.
For e.g.
public class Configuration {
private static Configuration configObj;
private static Database dbDetails;
private static Machine macDetails;
//...
//... many more modules
public static synchronized void createInstance(Properities envProps){
//Should create only one instance of Configuration
// and should also initialize Database & Machine objects.
}
public static Configuration getConfigObject(){
return configObj;
}
}
public class Database {
private static String dbConnectString;
public Database(String dbcs){
dbConnectString = dbcs;
}
public static String getDbConnectString(){
return dbConnectString;
}
}
public class Machine {
private static String hostname;
private static String loginUsername;
public Machine(String hostname,String loginUsername){
this.hostname = hostname; //It may include some trimming/cleaning
this.loginUsername = loginUsername;
}
public static String getHostName(){
return hostname;
}
}
PS: Just a sample typed-in code for the understanding of my problem statement.
Expectation : The expectation now is that when trying to get the hostname, I should have a single point of access via Configuration static object (assuming that I have initialized all member variables successfully) i.e.
String hostname = Configuration.getHostname();
OR
String hostname = Configuration.getConfigObject().getHostname();
Current Issue :
How to create one static object that will refer to all methods using either composition or inheritance (Conceptually, composition would be the right approach).
Multiple Inheritance would have solved the issue but Java doesn't support so ruled out. Cannot consider Interfaces either because overriding all methods is tedious & lengthy & the parameters/methods will keep changing over-time.
All suggestions are welcome even if it requires to scrap this design pattern & try something different.
You will not be able to "automatically" delegate static calls to modules. And even if the calls were not static, as you stated, Java does not support multiple inheritance.
Option 1:
Have your main Configuration class provide static methods that return instances to your modules. Whenever you want to read a configuration entry, first get the module instance, then query the entry itself:
Configuration.getDatabaseConfiguration().getServerName();
This method has the advantage that it is very clear which part of your configuration you are referring to. If you would just use Configuration.getServerName(), you cannot distingish whether you want to retrieve the database's server name, or the webserver's.
Option 2:
If you are able to use Java 8 and your configuration is large, but very simple (statically known at compile time or extractable from very few instances), you could consider using the new default interface methods (https://blog.idrsolutions.com/2015/01/java-8-default-methods-explained-5-minutes/).
You would then create an interface for each module, where all getters have default implementations. Your main configuration class would implement all the module interfaces without overriding any of the methods. This way all configuration entries can be queried from one object, but you still have to obtain this object by a static method. This is as close to multiple inheritance as you can get. I would definitely recommend option 1 though.

Conditionally inherit from class

I have following class inheritances (A is my parent class):
In some cases, X and Y need some extra fields and methods. So what I basically need is this:
I don't want to extend X and Y to give their child classes exact the same fields and methods due to duplicate code.
How to handle this? Is the only solution a delegate?
Update: Real-world example:
I'm importing data from different file types:
Package my_application.core:
public class ImportFile { // the "A"
protected final Path path;
}
public class CsvImportFile extends ImportFile { // the "X"
private final String delimiter;
}
public class FixedLengthImportFile extends ImportFile { // the "Y"
// nothing new
}
public class XmlImportFile extends ImportFile {
private final String root;
}
Sometimes the first lines of a file contain heads/titles instead of data. So here an example extension which allows to set a start line for csv and fixed-length files:
Package my_application.extension.line_start:
public class ExtensionLineStartImportFile { // the "B"
protected final int lineStart;
// some methods
}
So if the user chooses to use the extension line_start, CsvImportFile and FixedLengthImportFile should get the properties of ExtensionLineStartImportFile.
Side node: Since I have multiple extensions which do different things and these extensions should be easy to add to/remove from the application, I don't want to merge them all into the "core".
Factory pattern - this is quite an architectural issue and this pattern should be the answer for Your problem
You cannot have "conditional inheritance" in Java. Either you extend a class, either you don't. Changing the legacy chain implies recompiling the application.
If a C extends B extends A but B is not on the classpath, the class loading of C will fail.
The only solution I see here is to integrate this logic into your code (or have as many implementations as there are possible combinations).
So, yes, delegates would be a way (probably the only one to have logic on your classpath only when you need it). Having multiple ugly ifs in your code is another.

Get the name of the functions called by a class

There are two classes A and B in the same package.
how to get name of the functions of class A called by class B.
Restriction is that the code of A and B cannot be modified.
You cannot use Java reflection to do static code analysis tasks like this. The reflection APIs don't provide the information that is needed.
Off the top of my head, I can think of two approaches that will work:
If you only have the ".class" files, then you can use a bytecode library such as BCEL to load the classes and traverse them to identify all of the method calls.
If you have source code, you could also use some existing Java parser library to create ASTs for your code and analyse them.
(The first approach is probably simpler if all you want is a list of class and method names.)
Reflection can be very useful, but very complicated if you don't understand it.
If you have the name of the class, and want to print the methods:
Class c = Class.forName(the_class_name);
for(Method m : c.getMethods()) {
System.out.println(m.toString());
}
If you want the name of a class given any Object:
String className = the_object.getClass().getName();
A combination of the two could look like this:
for(Method m : the_object.getClass().getMethods())
System.out.println(m.toString());
I think what you are asking for is the names of all the methods from A that B calls.
That can't really be done with reflection, mostly because Java doesn't provide any method for doing this.
The API, as always, provides more information. If you look through there, you might come up with a simple work around.
"Class of all the functions called by class A or class B" is confusing. But, If You want to get the class and function name of caller to a method detectsName described in your class A , then following code will be useful to you.
public class A {
public void detectsName() {
Throwable t = new Throwable();
StackTraceElement traceLine = t.getStackTrace()[1];
// t.printStackTrace();
String className = traceLine.getClassName();
String methodName = traceLine.getMethodName();
int lineNumber = traceLine.getLineNumber();
System.out.println(className);
System.out.println(methodName);
System.out.println(lineNumber);
}
}
If you call this method from any other class say - B, it will be detected.
public class B {
public static void main(String[] args) {
A a = new A();
a.detectsName();
}
}
Dependency Finder can do queries for this. Its approach is to generate meta data in XML and then use regexp based comparison. You may be specifically looking for feature called 'closure' with inbound reference..

Categories

Resources