How to initialize members of App without running the App (main)? - java

I have a class MyClass, which extends App. The thing is that, inside MyClass, there is a variable myValue that I need to initialize, without actually running the app. The reason for this is because I want to run unit tests of the methods of MyClass in a non-interactive way.
class MyClass extends App {
val myValue = "A value that I need to run the unit tests"
def myMethod: Unit = "A method that needs to be unit-tested and uses " + myValue
/* ... main (interactive) code that is not supposed to run in the unit test... */
}
So, the question is: How can I initialize members of App without running the app (main)?

From scaladocs of App trait:
==Caveats==
It should be noted that this trait is implemented using the DelayedInit functionality, which means
that fields of the object will not have been initialized before
the main method has been executed.
It seems that your only option is to declare main method def main(args: Array[String]): Unit = ... as you would do in Java instead of extending App.

Related

Main method works for java, but not scala

I have a module in intellij, where I can create main methods in java which run perfectly, but when I create them in scala and attempt to run them, I get the following:
Error: Could not find or load main class xxx
My project relies on both java and scala classes. What do I need to do to allow scala main classes to run?
EDIT:
As requested, here's an excerpt of the main class I'm trying to run with scala. I know there's nothing wrong with the code because it works when I initialize the code in intellij as a scala project. The problem here is that I started with a blank project, so I don't know what magic intellij did behind the scenes to make the scala main classes run properly.
object WebProxyServer extends Logging {
def main(args: Array[String]): Unit = {
// implementation
}
}
class WebProxyServer() {
}
The easiest way to run Scala code is to create an object that extends App, like this:
object Main extends App {
println("Hello World")
}
Scala will execute all the code in the object when it is created. (The arguments are available in the args member of App)
To run this from IntelliJ, select "Run->Edit Configurations", then click "+" and select "Application" and fill in the dialog. The drop-down for the "Main Class" parameter should include all objects that extend App, so pick the class you want to run. Once this is done, your Main should appear on the "Run" menu.
You can have multiple classes that extend App and multiple items in the Run menu. I use this to debug specific parts of the code from the IDE without having the run the main program.
You can also create an object with a main method like this:
object Main {
def main(args: Array[String]): Unit = {
println("Hello World")
}
}
Once this is built you can add Main as a "Main Class" in IntelliJ as described above. All objects with a main method will also appear in the "Main Class" drop-down.
Both approaches are acceptable, but don't combine the two. That is, don't inherit from App and then override the main method in App.
To add Scala code to an existing Java module in Intellij, right click on the module name (usually the top level folder in the project view), and click "Add Framework Support", then check Scala in your list of options.
To add Scala code to a new module in an Intellij project, goto File -> New Module, and choose Scala from the list of options.
If your directory structure looks like this:
src
|
|-main
|
|-java
| |-....java packages
|
|-scala
|-....scala packages
Then don't forget to right click your scala directory in the project view and choose Mark Directory As -> Sources Root
first try check the SDK configuration to your IDE and if this cause you error.
object WebProxyServer {
def main(args: Array[String]): Unit = {}
}
then try extends App and override your main(args: Array[String]) if needed
Make sure you're adding the main method to objects, not classes. The main method needs to be static. You can add a companion object, which is just an object with the same name as the class, to contain the main method if you want to add a main method to an existing class.
class MyApp {
// bad main method; will not run
def main(args: Array[String]): Unit = println("hello world")
}
// companion object to MyApp class
object MyApp {
// good main method; will run fine
def main(args: Array[String]): Unit = println("hello world")
}

PowerMockito.whenNew is not creating mock actual instance is created

I have a constructor call in my method under test. I want to mock it because tries to launch a UI. I have mocked the input for constructor as well but still it is trying to create actual instance.
Production Code :
public void methodToTest() {
SaveAsDialog sd = new SaveAsDialog(getSite().getShell());
sd.setOriginalFile(file);
sd.open()
}
Test Code :
Shell mockShell=Mockito.mock(Shell.class);
IEditorSite site = Mockito.mock(TestEditorSite.class);
Mockito.when(site.getShell()).thenReturn(mockShell);
SaveAsDialog dialogMock=Mockito.mock(SaveAsDialog.class);
PowerMockito.whenNew(SaveAsDialog.class).withArguments(site.getShell()).thenReturn(dialogMock);
am I missing any thing here, when SaveAsDialog sd = new SaveAsDialog(getSite().getShell()); line is called it is creating actual instance.
I am running my test with
#RunWith(PowerMockRunner.class)
#PrepareForTest({SaveAsDialog.class})
You should pass in the instance of SaveAsDialog into your class under test as constructor parameter. This would make mocking it quite easy using plain Mockito.
If you rather want to surrender to your bad design you have to use PowerMock correctly which means you also have to preparer your class under test for mocking:
#PrepareForTest({SaveAsDialog.class,YourTestedClass.class})

Dynamically loading Groovy scripts into app server

I have a Java Spring app running in Tomcat that is meant to perform various processing rules based on incoming files. Because the file types and rules change, I would like to use Groovy to dynamically load new/changed functionality without having to recompile/restart the Java application each time.
Following the "Dynamically loading and running Groovy code inside Java" from the Groovy documentation,
GroovyClassLoader gcl = new GroovyClassLoader();
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy");
Object aScript = clazz.newInstance();
MyInterface myObject = (MyInterface) aScript;
myObject.interfaceMethod();
I created my version of SomeName.groovy that implements MyInterface and modified my Java app to then create an instance of that class as shown above. I know that my Groovy file is being read correctly because if I print out myObject.getClass().toString it shows the correct object type as defined in SomeName.groovy; however, when it gets to point of calling one of the implemented methods (myObject.interfaceMethod()) it doesn't do anything.
I've tested this approach in a Java application outside of Tomcat and it worked so I'm uncertain as to why running this inside of an app server would cause it to break. Also, I've confirmed that groovy-all-2.1.8.jar is included in my project.
Thanks in advance for any information that you can provide that might shed some light on why the dynamic loading might be failing.
Thx.
The form of the parseClass() method that you are using does not look at any external file at all. Instead it treats the first String argument (myStringwithGroovyClassSource in your case) as if it were the text content of a Groovy source file, and the second String argument (the literal "SomeName.groovy" in your case) as if it were the name of that file. This method does not open or parse any ACTUAL file at all.
To make this code work as is you would have to predefine the variable myStringwithGroovyClassSource. The overall effect would look something like this:
def myStringwithGroovyClassSource = """
class SomeName implements MyInterface {
def prop1 = 1, prop2 = 2
def interfaceMethod() { println prop1 }
}
"""
interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy")
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()
Now, on the other hand, if, as you say, you already have an external uncompiled Groovy source file named SomeFile.groovy that you wish to bring into your script via the GroovyClassLoader, then you need to change your existing code to something like this:
interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass("SomeName.groovy" as File)
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()
If the code in the file is valid-when-compiled, then you should have no trouble getting this to work.

Pass a parameter with JUnitCore.run() method

I have one Test launcher class to run different type of tests by loading and executing classes generated to run with selenium. In this I am launching test by giving a string name and then running it with JUnitCore.run() method
Here is sample code for that:
Class clsTestStep = Class.forName("CheckLogin",true,new ClassLoader() {});
JUnitCore junit = new JUnitCore();
junit.addListener(new ExecutionListener());
org.junit.runner.Result runner= junit.run(clsTestStep);
Can Anyone tell me if I want to pass some object or property value with this class then How can I achieve it?
Note that I want that object to be available in 'CheckLogin' class at test running time, i.e username/password passed from launcher class to 'CheckLogin' class.

Class<Test> object not the same type as a Test object? Junit

I'm trying to write some code which recursively adds TestSuites in a project to a suite of suites located at the root of the package hierarcy.
I've already written the code which returns a Collection object which contains a File object for each Test Suite found in my project.
I'm now trying to loop through them and add them to a TestSuite in a file called AllTests.java:
public static Test suite() throws IOException, ClassNotFoundException {
TestSuite suite = new TestSuite();
//Code not included for getTestSuites() in this snippet.
Collection<File> testSuites = getTestSuites();
for(File f: testSuites) {
//Truncate the path of the test to the beginning of the package name
String testName = f.getAbsolutePath().substring(f.getAbsolutePath().lastIndexOf("net"));
//Replace backslashes with fullstops
testName = testName.replaceAll("\\\\", ".");
//Take the .class reference off the end of the path to the class
testName = testName.replaceAll(".class", "");
//Add TestSuite to Suite of Suites
Class<? extends Test> test = (Class<? extends Test>) AllTests.class.getClassLoader().loadClass(testName);
suite.addTest(test);
}
Unfortunately I am getting the following compiler error on the suite.addTest(test) line:
The method addTest(Test) in the type
TestSuite is not applicable for the
arguments (Class < capture#3-of ? extends Test>)
Am I making a fundamental mistake by assuming that a Class< Test > reference and a Test reference are one and the same?
Yes, you are making a fundamental mistake by assuming that a Class< Test > reference and a Test reference are one and the same.
You need an instance of a Class that extends Test, not an instance of a Class object whose definition extends Test (Classes are objects too in java).
TestSuite.addTest needs a Test class instance; not just a Class object.
You could try using Class.newInstance() if your tests can be (they should) instantiated without parameters.
--
A maybe better strategy is to start using Maven; which automatically runs all Test classes in the src/test/java source folder. But that can be a quite big overhaul :).
Class<Test> describes the concept of class Test -- its fields, methods, and other stuff described by the Java code when defining class Test. There is generally (to keep classloaders out of this discussion) one instance of Class<Test> across the JVM, since there is basically just one Test class.
The same applies for every Test subclass -- there is generally one instance of Class<TestSubClass> for every TestSubClass.
On the other hand, there can be any number of Test objects.
Java allows you to create Test objects from a Class<Test>, by invoking newInstance against your Class<Test> instance. So basically, change your line from:
suite.addTest(test);
to
suite.addTest(test.newInstance());
And handle all potential exceptions.
Method you are using expects instance of Test (sub)class.
The one you are after is probably addTestSuite(Class testClass) which allows adding classes.

Categories