Junit and java classes. - java

The below is a simple java class file that checks if the file provided by the user is under the home directory or not. It throws an exception when the file is not under the home directory.
public class A {
public static void main(String args[]) {
if (new A().processArgs(args[0]) {
throw Exception("Not under home directory");
}
}
// A simple method to check if the file is at home directory
private boolean processArgs(String s) {
File f = new File(s);
String userHome = System.getProperty("user.home");
if (s.startsWith(userHome) && f.exists() && additionalLogic())
return true;
else
return false;
}
// Additional business Logic
private boolean additionalBusinessLogic() {
// Do wonderful things.
}
}
I want to write a simple Junit test case for testing the java class. Primary concern to test is the additional Business logic method. Is there a way I can bypass the check where directory must be under user home directory.
I am not comfortable in adding logic in my main class to make it aware of the Junit classes. Is there a better way to do this?

While there's nothing wrong with fab's solution, I decided to write another:
public class Main {
public static void main(String args[]) {
// TODO: Should check args length
Validator validator = new Validator();
validator.validateArgs(args[0]);
}
}
public interface Configuration {
public String getHomeDirectory();
}
public class DefaultConfiguration implements Configuration {
public String getHomeDirectory() {
String home = System.getProperty("user.home");
if (home == null) {
throw new RuntimeException("User home directory is not set!");
}
return home;
}
}
public class Validator {
private Configuration configuration;
public Validator() {
this(new DefaultConfiguration());
}
public Validator(Configuration configuration) {
this.configuration = configuration;
}
// A simple method to check if the file is at home directory
public void validateArgs(String s) {
File f = new File(s);
if (!s.startsWith(configuration.getHomeDirectory()) || !f.exists() || !additionalBusinessLogic())
throw new RuntimeException("Not under home directory!");
}
// Additional business Logic
private boolean additionalBusinessLogic() {
// TODO...
return true;
}
}
public class ValidatorTest {
#Test
public void validateValidArgsTest() {
final String homeDirectory = ".."; // TODO
String existingFile = homeDirectory + ".."; // TODO
new Validator(new Configuration() {
public String getHomeDirectory() {
return homeDirectory;
}
}).validateArgs(existingFile);
}
#Test(expected = RuntimeException.class)
public void validateInvalidArgsTest() {
String existingFile = ".."; // TODO
new Validator(new Configuration() {
public String getHomeDirectory() {
return "-INVALID PATH-";
}
}).validateArgs(existingFile);
}
}

You don't need to make the class aware of the test to make it more testable. You just need to decouple the additional logic from the i/o stuff, which will also result in a better design:
public class A {
private WonderfulThingsDoer wonderfulService;
public void main(String args[]) {
wonderfulService = new WonderfulThingsDoer();
if (processArgs(args[0]) {
throw Exception("Not under home directory");
}
}
// A simple method to check if the file is at home directory
private boolean processArgs(String s) {
File f = new File(s);
String userHome = System.getProperty("user.home");
if (s.startsWith(userHome) && f.exists() && additionalBusinessLogic())
return true;
else
return false;
}
// Additional business Logic
private boolean additionalBusinessLogic() {
return wonderfulService.doWonderfulThings();
}
}
public class WonderfulThingsDoer {
public boolean doWonderfulThings() {
// Do wonderful things.
return true;
}
}
Voilá, extracted a testable unit.

Simply don't hard code the "user.home"
Create a field home, that you change in the unit code, to point to the test directory:
public class A {
private static String homeDir;
protected static void setHomeDir(String home) {
this.homeDir = home;
}
public static void main(String args[]) {
if (homeDir == null) {
homeDir = System.getProperty("user.home");
}
A a = new A();
if (a.processArgs(args[0]) {
throw new InvalidArgumentException("Not under home directory");
}
}
// A simple method to check if the file is at home directory
protected boolean processArgs(String s) {
File f = new File(s);
if (s.startsWith(A.homeDir) && f.exists() && additionalLogic())
return true;
else
return false;
}
// Additional business Logic
private boolean additionalBusinessLogic() {
// Do wonderful things.
}
}
Now in the Unit Test, set the homeDir to your test directory
public void testMainHomeExisting() {
A a = new A;
String home = "./testdata/";
A.setHomeDir(home);
String[] args = new String[]{home}; // hope this compiles otherwise fix it
// no assert needed here, if test fails, an Exception is thrown
A.main(args);
}
Now a test case for home not existing
public void testMainHomeNotExisting() {
A a = new A;
String home = "./notExistingFooBarFooFoo/";
A.setHomeDir(home);
String[] args = new String[]{home}; // hope this compiles otherwise fix it
// no assert needed here, if test fails, an Exception is thrown
try {
A.main(args);
// if code works the next line should not be reached:
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException ex) {
// as expected got IllegalArgumentException
}
}

Just make a Test for the core business method additionalBusinessLogic only. You don't need to call main.

I see no reason to call main.
When you're writing a unit test, you want them to be modular enough to call without relying too much on external methods - and what you can't call you can mock, using something like EasyMock, PowerMock or Mockito.

I would change the method you want to test...
Remove the access modifier
Pass in the File variable you need to be able to do your logic
boolean additionalBusinessLogic(File f)
This will allow a test class in the same package to invoke the method. If you leave it private, no other classes will be able to call it.
Once you can call the method you want to test, the test class is easy...
public class MyClassTest {
#Test
public void additionalBusinessLogic_shouldFoo_whenSomeCondition() {
// setup
A a = new A();
File mockFile = mock(File.class);
// other setup stuff
// execute
boolean result = a.additionalBusinessLogic(mockFile);
// assert
// verify whatever you need to
}
}
For a good mocking framework, I would suggest Mockito.

Related

How do I test a Java Code Generator in NetBeans?

I am starting to program a Code Generator for NetBeans 8, and I am having trouble figuring out the best way to test its invoke() method.
The code generator I want to test is basically like this:
(imports here)
public class MyCodeGenerator implements CodeGenerator {
private final JTextComponent textComponent;
private final CompilationController controller;
MyCodeGenerator(final Lookup context) {
textComponent = context.lookup(JTextComponent.class);
controller = context.lookup(CompilationController.class);
}
#Override
public String getDisplayName() {
return "Generate Some Code...";
}
/**
* This will be invoked when user chooses this Generator from Insert Code
* dialog
*/
#Override
public void invoke() {
if (textComponent != null && controller != null) {
controller.toPhase(Phase.RESOLVED);
//do more things with the source code;
}
}
}
I want to use a mocked (Mockito) object for Lookup, to pass to the MyCodeGenerator's constructor. The mock should return the JTextComponent and the CompilationController.
I know I can provide a JTextComponent with the test code, but I hit the wall when I need to provide a CompilationController.
I can create a temporary java source file with the same content as the JTextComponent, but I could not find a way to create a CompilationController (or WorkingCopy) from it.
This is what I tried so far (my test method):
#Test
public void testInvoke() throws ParseException, IOException {
System.out.println("invoke");
final ExtractControllerTask extractTask = new ExtractControllerTask(
Phase.RESOLVED);
final StringBuilder builder = new StringBuilder(100);
final JTextComponent textComponent;
final Document document;
final FileObject javaTestFile;
final OutputStream outputStream;
final JavaSource source;
builder.append("public class Clazz {");
builder.append("private int a = 2;");
builder.append("}");
textComponent = new JTextArea(builder.toString());
document = textComponent.getDocument();
document.putProperty(BaseDocument.MIME_TYPE_PROP, "text/x-java");
javaTestFile = FileUtil.createData(new File(
"/tmp/javaTestSourceFile.java"));
outputStream = javaTestFile.getOutputStream();
outputStream.write(builder.toString().getBytes());
outputStream.flush();
source = JavaSource.forFileObject(javaTestFile);
assertNotNull(source);
source.runUserActionTask(extractTask, true);
assertNotNull(extractTask.controller); //FAILS HERE
}
This is the code for ExtractControllerTask:
private static class ExtractControllerTask implements
Task<CompilationController> {
private final Phase targetPhase;
private CompilationController controller;
private ExtractControllerTask(final Phase phase) {
this.targetPhase = phase;
}
public void run(final CompilationController compControler) {
try {
compControler.toPhase(this.targetPhase);
this.controller = compControler;
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
What surprises me is that the run method in ExtractControllerTask is never called.
I really need to test my code but I can't find the proper way. Maybe the approach is completely wrong.
Can anyone suggest how to achieve this?

specify file type in method parameter

I was wondering if it was possible to require a certain type of file in class constructor?
For example:
private class name(File location.txt)
I want to have a different constructor for each type of file format that I am going to support. I could write a method that checks the file and sends it to the appropriate method, but was wondering if it was a possibility to skip that logic?
I hope this mini factory sample would work for you:
public class Test {
private FileReaderFactory fileReaderFactory = new FileReaderFactory();
public static void main(String[] args) {
String fileTxt = "test1.txt";
String filePdf = "test2.pdf";
Test test = new Test();
FileTypeI filereaderTxt = test.fileReaderFactory.createFromExtension(fileTxt);
FileTypeI filereaderPdf = test.fileReaderFactory.createFromExtension(filePdf);
filereaderTxt.readFile();
filereaderPdf.readFile();
}
public interface FileTypeI {
void readFile();
}
class TextFileReader implements FileTypeI {
#Override
public void readFile() {
//Code to read Text File
}
}
class PDFFileReader implements FileTypeI {
#Override
public void readFile() {
//Code to read PDF File
}
}
class FileReaderFactory {
public FileTypeI createFromExtension (String filename) {
FileTypeI returningValue = null;
if (filename != null && filename.endsWith(".txt")) {
returningValue = new TextFileReader();
}
else if (filename != null && filename.endsWith(".pdf")) {
returningValue = new PDFFileReader();
}
return returningValue;
}
}
}

Java Reflection: Find method usage in custom AbstractProcessor

I'm newbie in reflection. Is there any way to detect where is an specific method invoked? For example:
public class MyClass {
public static void method(){
//DO SOMETHING
}
}
public class Test {
public test(){
MyClass.method();
}
}
public class MyProcessor extends AbstractProcessor {
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Method method = MyClass.class.getDeclaredMethod("method");
Class classWhereMethodIsInvoked = obtainClassWhereMethodIsInvoked(method);
}
public Class obtainClassWhereMethodIsInvoked(Method method) {
//here I want to search one class that invoke that method, in this case Test.class
}
}
is something like this possible or I am going crazy?
As mentioned in the comments, Apache BCEL is suitable for your problem. Such libraries are often particularly used for determining compile-time information such as method usage and control flow analysis from the generated bytecode, and such information are difficult, if not impossible, to retrieve using reflection. If you use the BCEL solution, you probably no longer require a custom annotation processor.
But since you already seem to be using a custom annotation processor, the whole point of it is to be able to process annotations in the source files. So one way is to define a custom annotation that marks a method being called, and have the custom processor read these annotations to know which classes call which methods:
#CallerClass("MyClass.method")
public class Test {
public test() {
MyClass.method();
}
}
In the above (trivial) example, a custom CallerClass annotation marks that a class calls the method specified in the annotation's element inside parentheses. The annotation processor can read this annotation and construct the caller information.
Yes it doable if you really want it. You can use the classLoader to search through the class path and scan for the method name through all the class files. Below is a very simplistic example to show that it is doable. In the example below I find usage of the "println" method being used in this class. Essentially you can just broaden the scope from one file in my example to all the class files.
public class SearchClasses {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException {
// InputStream is = SearchClasses.class.getClassLoader().getResourceAsStream("resources.SearchClasses.class");
InputStream is = new FileInputStream(new File("build/classes/resources/SearchClasses.class"));
boolean found = false;
Scanner scanner = new Scanner(is);
while (scanner.hasNext()) {
if (scanner.nextLine().contains("println")) {
System.out.print("println found");
found = true;
break;
}
}
if (!found) {
System.out.print("println NOT found");
}
}
public static void testMethod() {
System.out.println("testing");
}
}
In my IDE I had to use the FileInputStream to access the class file I was searching in.... but if you are searching through jar files then you can use the classLoader instead. You would need mechanism to search through all of the class path... this is not impossible but I left it our for brevity.
EDIT: Here is an attempt to get it working completely.. searches all files in class path for your method.
public class SearchClasses {
/**
* #param args the command line arguments
* #throws java.io.FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException, IOException {
printAllFileWithMethod("println");
}
public static void printAllFileWithMethod(String methodName) throws FileNotFoundException, IOException {
Enumeration<URL> roots = SearchClasses.class.getClassLoader().getResources("");
List<File> allClassFiles = new ArrayList<>();
while (roots.hasMoreElements()) {
File root = new File(roots.nextElement().getPath());
allClassFiles.addAll(getFilesInDirectoryWithSuffix(root, "class"));
}
for (File classFile : allClassFiles) {
InputStream is = new FileInputStream(classFile);
boolean found = false;
Scanner scanner = new Scanner(is);
while (scanner.hasNext()) {
if (scanner.nextLine().contains(methodName)) {
System.out.print(methodName + " found in " + classFile.getName() + "\n");
found = true;
break;
}
}
}
}
public static void testMethod() {
System.out.println("testing");
}
static List<File> getFilesInDirectoryWithSuffix(File dir, String suffix) {
List<File> foundFiles = new ArrayList<>();
if (!dir.isDirectory()) {
return foundFiles;
}
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
foundFiles.addAll(getFilesInDirectoryWithSuffix(file, suffix));
} else {
String name = file.getName();
if (name.endsWith(suffix)) {
foundFiles.add(file);
}
}
}
return foundFiles;
}
}
You could define your own mechanism. Use a Map to store the caller of each method :
public static Map<Method, List<String>> callStack = new HashMap<Method, List<String>>();
public static void registerCaller(Method m)
{
List<String> callers = callStack.get(m);
if (callers == null)
{
callers = new ArrayList<String>();
callStack.put(m, callers);
}
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
callers.add(stackTraceElements[3].getClassName());
}
The target class :
class MyClass
{
public static void method()
{
registerCaller(new Object(){}.getClass().getEnclosingMethod());
// DO SOMETHING
}
}
Some caller classes :
package the.package.of;
class Test
{
public void test()
{
MyClass.method();
}
}
class Foo
{
public void bar()
{
MyClass.method();
}
}
And finally, the test :
new Test().test();
new Foo().bar();
Method method = MyClass.class.getDeclaredMethod("method");
for (String clazz : callStack.get(method))
{
System.out.println(clazz);
}
Prints :
the.package.of.Test
the.package.of.Foo
Well, if you use Eclipse as an IDE, you can find the complete call hierarchy via "Open Call Hierarchy" function. This will find all usages of your method in any open Eclipse projects.
However, if you want to find out during runtime programmatically, then you need to integrate some library, that can statically analyze the bytecode of your classpath for use of your method.
You can obtain stack trace right inside the test method:
public class Test {
public void test() {
System.out.println(getCallerClass());
}
public static String getCallerClass() {
for (StackTraceElement e: Thread.currentThread().getStackTrace()) {
if (!"java.lang.Thread".equals(e.getClassName()) && !e.getClassName().equals(Test.class.getName()))
return e.getClassName();
}
return null;
}
}

How to call parent class objects within a subclass?

I'm not sure if I'm asking this right, as I'm attempting to teach myself Java. I have a class which contains my main method, and within this class are several subclasses that need access to my user settings using java.util.Properties. I have to create the properties object in every subclass in order to make it work, and I can't reference the object using configFilePath, it must be null. I'm wondering if I can create this public object within the parent class, so I don't need to create it in all of its subclasses? Here is my code, I'm really not sure I'm doing this right although it works.
public class Frame1 extends JFrame {
Settings config = new Settings(); //this is the object I want to reference within subclasses
class Update extends SwingWorker<Integer, Void> { //first subclass
#Override
protected Integer doInBackground() throws Exception {
Settings config = new Settings(configFilePath); //yet I have to create the object within every subclass, this time an argument is required.
String templateDir = config.getProperty("templatedir");
String writePath = config.getProperty("outputdir");
//do some logic code, not required for my question
}
#Override
protected void done() {
Update2 update2 = new Update2();
update2.execute(); //start the next subclass which also needs access to Settings(configFilePath)
}
}
}
public class Settings extends JFrame {
String configFilePath = "C:/path/to/settings.properties";
Properties properties = new Properties();
public Settings(String configFilePath) throws IOException {
this.configFilePath = configFilePath;
FileInputStream fis = null;
try {
fis = new FileInputStream(configFilePath);
properties.load(fis);
} catch (FileNotFoundException e) {
setDefaults();
} finally {
if (fis != null) {
fis.close();
}
}
}
}
I'm not sure if I'm doing this right or not, it seems to work but seems to be rather redundant having to create the config object every time I need to access my user settings. I hope this hasn't been asked before, and if it has please link me, as I could not find it.
You can create the Setting class as a Singleton pattern, here is one example:
public class Settings extends JFrame{
String configFilePath = "C:/path/to/settings.properties";
Properties properties = new Properties();
private static Settings instance;
public static Settings getInstance(){
if(instance==null){
instance = new Setting();
}
return instance;
}
private Settings() throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(configFilePath);
properties.load(fis);
} catch (FileNotFoundException e) {
setDefaults();
} finally {
if (fis != null) {
fis.close();
}
}
}
}
Usage in any other class of your system:
Settings.getInstance().getProperty("...");
From Update you can use Frame1.this to access the this of Frame1 (because Update is an inner class of Frame1).
Then to access config you can use Frame1.this.config.
Here is a working example:
public class PrefixerFactory {
private String prefix; // Used by Prefixer
public PrefixerFactory(String prefix) {
this.prefix = prefix;
}
public Prefixer createPrefixer() {
return new Prefixer();
}
public class Prefixer { // Inner class
public String addPrefix(String value) {
// Using "prefix" from PrefixerFactory
return PrefixerFactory.this.prefix + value;
}
}
public static void main(String[] args) {
Prefixer helloPrefixer = new PrefixerFactory("Hello ").createPrefixer();
Prefixer goodbyePrefixer = new PrefixerFactory("Good bye ").createPrefixer();
System.out.println(helloPrefixer.addPrefix("world")); // Hello world
System.out.println(goodbyePrefixer.addPrefix("world")); // Good bye world
}
}

Configuration not being reloaded

I'm having an issue with my configuration management class, it is not getting reloaded.
Let me show you part of my code:
public class ConfigurationManager extends XMLConfiguration
{
private static final Logger log = LoggerFactory.getLogger(ConfigurationManager.class);
private static final long serialVersionUID = 1L;
public static final String CONFIG_FILE_PATH = "/config.xml";
private static volatile ConfigurationManager instance = null;
private static Object lock = new Object();
// Instance management methods
public static ConfigurationManager getInstance()
{
return getInstance(CONFIG_FILE_PATH);
}
public static ConfigurationManager getInstance(String cfg)
{
if(instance == null)
{
synchronized(lock)
{
if(instance == null)
{
try
{
instance = new ConfigurationManager(cfg);
instance.dumpConfigurationToLog();
}
catch(Exception e)
{
log.error("Error calling getInstance. Method params", e);
}
}
}
}
return instance;
}
private Object loadedCfg;
private int reloadInterval;
private void dumpConfigurationToLog()
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
this.save(bos);
bos.flush();
}
catch(Exception e)
{
log.error("Error calling dumpConfigurationToLog. Method params", e);
}
}
#Override
public void configurationChanged(ConfigurationEvent event)
{
log.info("Enter Method configurationChanged params: {}", event);
if(event.isBeforeUpdate() == false)
{
makeUpdates();
log.info("Configuration file: {} has changed and reloaded...", loadedCfg);
dumpConfigurationToLog();
}
log.info("Return Method configurationChanged");
}
private void updateReloadInterval()
{
int newReloadInterval = getInt("global.reloadInterval") * 1000;
if(reloadInterval != newReloadInterval)
{
reloadInterval = newReloadInterval;
if(getReloadInterval() > 0)
{
FileChangedReloadingStrategy reloadStrategy = new FileChangedReloadingStrategy();
reloadStrategy.setRefreshDelay(getReloadInterval());
this.setReloadingStrategy(reloadStrategy);
}
else
if(getReloadInterval() == 0)
{
this.setReloadingStrategy(new InvariantReloadingStrategy());
}
else
{
log.error("Invalid reload interval for ConfigurationManager: {}", getReloadInterval());
}
}
}
private ConfigurationManager(String cfgFile) throws Exception, ConfigurationException
{
super();
loadedCfg = cfgFile;
if(System.class.getResource(cfgFile) != null)
this.setURL(System.class.getResource(cfgFile));
else
this.setURL(getClass().getResource(cfgFile));
this.load();
makeUpdates();
this.addConfigurationListener(this);
this.setThrowExceptionOnMissing(true);
}
private void makeUpdates()
{
updateReloadInterval();
}
public int getReloadInterval()
{
return reloadInterval;
}
}
Now that code works perfectly fine, I can read the configuration file, and work with it with no major problems, the issue is that it never gets reloaded on configuration changes. I've tried setting breakpoints and so, but it never gets into configurationChanged method.
Does anybody see something wrong here?
Well, after testing and analyzing, I've got to this conclusion, in order to have configurationChanged called, I need to make an explicit call to get values from configuration.
And that is something I was not doing.
The thing got fixed when I did that.
You're calling makeUpdates() after setting your ConfigurationListener.
Additionally, calling load() is no guarantee that an Event will get fired.
Lastly, is there anything actually calling addProperty(), etc for this extended class?
Only a small side issue: resource bundles are cached, you can call clearCache, unfortunately not per bundle but per class loader.

Categories