How do I test a Java Code Generator in NetBeans? - java

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?

Related

How can I JUnit test these small serialize and json functions? in Android, Java

I've learnt how to unit test basic things within Android, e.g. getting and setting of methods as below etc. but when it comes to the more complex stuff like my actual code below, I'm a little flummoxed at what to do.
public class SurveyTest extends TestCase {
private Survey survey;
protected void setUp() throws Exception {
super.setUp();
survey = new Survey();
}
public void testGetId() {
long expected = (long) Math.random();
survey.setId(expected);
long actual = survey.getId();
Assert.assertEquals(expected, actual);
}
public void testGetTitle() {
String expected = "surveytitle";
survey.setTitle(expected);
String actual = survey.getTitle();
Assert.assertEquals(expected, actual);
}
My small code that I'm stuck on how to Junit Test in the format as above:
public abstract class PrimaryModel extends Observable implements Serializable{
protected void notifyModelChange()
{
setChanged();
notifyObservers();
}
public String serialize() throws IOException
{
ObjectOutputStream objOutStream = null;
ByteArrayOutputStream bytArrOutStream = null;
try
{
bytArrOutStream = new ByteArrayOutputStream();
objOutStream = new ObjectOutputStream(bytArrOutStream);
objOutStream.writeObject(this);
}
finally
{
String main = new String(bytArrOutStream.toByteArray());
objOutStream.close();
bytArrOutStream.close();
return main;
}
}
public static PrimaryModel deserialize(String data) throws IOException, ClassNotFoundException
{
ObjectInputStream objInputStream = new ObjectInputStream(new ByteArrayInputStream(data.getBytes()));
PrimaryModel obj = (PrimaryModel) objInputStream.readObject();
objInputStream.close();
return obj;
}
}
Something like a serialize/deserialize pair of methods is generally easily tested. You need to know that a round trip returns an object which is equivalent to the original.
private static class PrimaryModelSubclass extends PrimaryModel {
/* add methods as needed */
}
final PrimaryModel original = new PrimaryModelSubclass(7, "some string", 43.7);
final PrimaryModel wellTravelled = PrimaryModel.deserialize(original.serialize());
assertEquals(original, wellTravelled);
You will need hashCode and equals methods to be correctly defined as well.
Updated in response to comment

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
}
}

Junit and java classes.

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.

How to test file sizes with mockito in java?

I have method for which I need to create a JUnit test:
public class MyClass {
private String file1;
private String file2;
public void myMethodSpaceCheck(){
if (new File(file1).size() > new File(file2).size() {
throw new Exception .....
}
}
}
Is it possible to use Mockito to create that JUnit test?
When dealing with files in Java, my preferred option is to go with Apache VFS, as I can then treat them as any other POJO. Obviously, that's a lot of work when you are already stuck with the File API.
Another option is to forget Mockito entirely and write those files on the system. I usually avoid that, as it sometimes make it harder to have tests run in parallel on some systems.
For this specific situation, my solution is generally to provide a special class, say FileBuilder, that can instantiate new Files:
public class FileBuilder {
public java.io.File newFile(String pathname) {
return new java.io.File(pathname);
}
}
I then mock this class before passing it to MyClass, and instrument it as appropriate:
#Test(expected = Exception.class)
public void should_fail_when_file1_is_bigger_than_file2() {
FileBuilder mockFile1 = file(2L);
FileBuilder mockFile2 = file(1L);
FileBuilder mockFileBuilder = mock(FileBuilder.class);
when(mockFileBuilder.newFile("file1").thenReturn(mockFile1);
when(mockFileBuilder.newFile("file2").thenReturn(mockFile2);
new MyClass(mockFileBuilder).myMethodSpaceCheck();
}
private static File file(long length) {
File mockFile = mock(File.class);
when(mockFile.length()).thenReturn(length);
return mockFile;
}
(your example mentions File.size(); I assumed you meant File.length())
The actual implementation of MyClass would look like this:
public class MyClass {
private String file1;
private String file2;
private final FileBuilder fileBuilder;
public MyClass() {
this(new FileBuilder());
}
#VisibleForTesting
MyClass(FileBuilder fileBuilder) {
this.fileBuilder = fileBuilder;
}
public void myMethodSpaceCheck() //...
}

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