I often recommend Groovy's #Immutable AST transformation as an easy way to make classes, well, immutable. This always works fine with other Groovy classes, but someone recently asked me if I could mix those classes into Java code. I always thought the answer was yes, but I'm hitting a snag.
Say I have an immutable User class:
import groovy.transform.Immutable
#Immutable
class User {
int id
String name
}
If I test this using a JUnit test written in Groovy, everything works as expected:
import org.junit.Test
class UserGroovyTest {
#Test
void testMapConstructor() {
assert new User(name: 'name', id: 3)
}
#Test
void testTupleConstructor() {
assert new User(3, 'name')
}
#Test
void testDefaultConstructor() {
assert new User()
}
#Test(expected = ReadOnlyPropertyException)
void testImmutableName() {
User u = new User(id: 3, name: 'name')
u.name = 'other'
}
}
I can do the same with a JUnit test written in Java:
import static org.junit.Assert.*;
import org.junit.Test;
public class UserJavaTest {
#Test
public void testDefaultCtor() {
assertNotNull(new User());
}
#Test
public void testTupleCtor() {
assertNotNull(new User(3, "name"));
}
#Test
public void testImmutableName() {
User u = new User(3, "name");
// u.setName("other") // Method not found; doesn't compile
}
}
This works, though there are troubles on the horizon. IntelliJ 15 doesn't like the call to new User(), claiming that constructor is not found. That also means the IDE underlines the class in red, meaning it has a compilation error. The test passes anyway, which is a bit strange, but so be it.
If I try to use the User class in Java code directly, things start getting weird.
public class UserDemo {
public static void main(String[] args) {
User user = new User();
System.out.println(user);
}
}
Again IntelliJ isn't happy, but compiles and runs. The output is, of all things:
User(0)
That's odd, because although the #Immutable transform does generate a toString method, I rather expected the output to show both properties. Still, that could be because the name property is null, so it's not included in the output.
If I try to use the tuple constructor:
public class UserDemo {
public static void main(String[] args) {
User user = new User(3, "name");
System.out.println(user);
}
}
I get
User(0, name)
as the output, at least this time (sometimes it doesn't work at all).
Then I added a Gradle build file. If I put the Groovy classes under src\main\groovy and the Java classes under src\main\java (same for the tests but using the test folder instead), I immediately get a compilation issue:
> gradle test
error: cannot find symbol
User user = new User(...)
^
I usually fix cross-compilation issues like this by trying to use the Groovy compiler for everything. If I put both classes under src\main\java, nothing changes, which isn't a big surprise. But if I put both classes under src\main\groovy, then I get this during the compileGroovy phase:
> gradle clean test
error: constructor in class User cannot be applied to the given types;
User user = new User(3, "name");
required: no arguments
found: int,String
reason: actual and formal arguments differ in length
Huh. This time it's objecting to the tuple constructor, because it thinks it only has a default constructor. I know the transform adds a default, a map-based, and a tuple constructor, but maybe they're not being generated in time for the Java code to see them.
Incidentally, if I separate the Java and Groovy classes again, and add the following to my Gradle build:
sourceSets {
main {
java { srcDirs = []}
groovy { srcDir 'src/main/java' }
}
}
I get the same error. If I don't add the sourceSets block, I get the User class not found error from earlier.
So the bottom line is, what's the correct way to add an #Immutable Groovy class to an existing Java system? Is there some way to get the constructors to be generated in time for Java to see them?
I've been making Groovy presentations to Java developers for years and saying you can do this, only to now run into problems. Please help me save face somehow. :)
I did try your scenario as well, where you have a single project with a src/main/java and a src/main/groovy directory and ended up with compilation errors similar to what you saw.
I was able to use Groovy immutable objects in Java when I put the Groovy immutables in a separate project from the Java code. I have created a simple example and pushed it to GitHub (https://github.com/cjstehno/immut).
Basically it's a Gradle multi-project with all the Groovy code (the immutable object) in the immut-groovy sub-project and all the Java code in the immut-java project. The immut-java project depends on the immut-groovy project and uses the immutable Something object:
public class SomethingFactory {
Something createSomething(int id, String label){
return new Something(id, label);
}
}
I added a unit test in the Java project which creates a new instance of the immutable Groovy class and verifies its contents.
public class SomethingFactoryTest {
#Test
public void createSomething(){
Something something = new SomethingFactory().createSomething(42, "wonderful");
assertEquals(something.getId(), 42);
assertEquals(something.getLabel(), "wonderful");
}
}
This is not really ideal, but it works.
Related
I am new to scala. I have a requirement to execute the scala class using java.
My exact requirement is: I need to pass the entire scala class (file) as an argument to the java jar. That jar should read the scala code and execute it. I have searched many sites but did not find the appropriate answer. Is there any way to do the same?
Thank you in Advance.
Besides of your motivation to do that, it is for sure possible (I did it using my IDE - sbt project)
I just made scala class as below:
import com.google.common.base.Objects
class Car(_color: String, _valid: Boolean) {
val color: String = _color
val valid: Boolean = _valid
override def toString = Objects.toStringHelper(this).add("color",color).add("valid", valid).toString
}
After that I made class with main method to test it.
public class Test {
public static void main(String[] args) {
Car test = new Car("test", true);
System.out.println("test = " + test);
}
}
It compiled without any problems and the result was like below:
test = Car{color=test, valid=true}
Scala has its own compiler scalac whereas java uses javac. Since scalac compiles to class file that java can read and assuming that you are only using java libraries in the class then you can load the class in java. So what you need is to call scalac to compile the scala file and then load the generate class file using ClassLoader
I am fairly new to Java so forgive me if this is a silly question, but believe me when I say I really cannot find a solid answer.
This is what I'm working with:
So I'm testing a program, and the easiest way to keep it maintained and updated is to create my own library of "buttons". Everything in the library are small functions like "enterValidCredentials" and "clickLoginButton".
So let's take a look at my test cases. In a perfect world I'd be able to just:
public class progressCheck {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://mail.google.com/");
enterValidCredentials;
clickLoginButton;
}
}
enterValidCredentials and clickLoginButton exist in my library of classes. I know very well that that's not going to work as written above. What, literally, is the correct way to do this?
If it helps at all, my enterValidCredentials class looks like this:
public class loginPageButtons {
private WebDriver driver;
Actions actions = new Actions(driver);
public class enterValidCredentials { // This class enters in a valid username and valid password on the login page.
public void enterValidCredentials2() {
driver.findElement(By.cssSelector("input[type=\"text\"]")).clear();
driver.findElement(By.cssSelector("input[type=\"text\"]")).sendKeys("XXXXXXXX");
driver.findElement(By.cssSelector("input[type=\"password\"]")).clear();
driver.findElement(By.cssSelector("input[type=\"password\"]")).sendKeys("XXXXXXXX");
}
}
All my other functions follow a relatively similar structure (depending on their function, of course).
You can use a unit test to check single functionalities of your classes.
The most used library to create unit tests is JUnit.
If you use an ide (like IntelliJ or Eclipse) running the test can be done with a simple command exactly as running a main method.
If you need to create mocks of your objects you can use a library like Mockito (but there are many other valid alternatives).
Note: A mock is an object that has the same interface as a complex object that is difficult to use in a test environment (for example a db connection, a file handler, a network handler).
Here is an example, I tried to imagine your code and a possible test. I assumed that clickLoginButton returns an integer just to show a possible assert statement.
Example:
#Test
public static void testCredentials() {
WebDriver driver = new FirefoxDriver();
driver.get("http://mail.google.com/");
EnterValidCredentials enterValidCredentials = new EnterValidCredentials(); // Or create a mock if necessary
// Set values if necessary
int returnValue = enterValidCredentials.clickLoginButton();
assertEquals(returnValue, 1);
}
I have cloned a maven project on a new machine but I am having some problems with some of the dependencies as they don't seem to have been loaded.
One such case, is fj.Effect of Functional java. I am not sure if I am (manually) adding the right library.
In the code, I have:
private Effect<EventDBEvent> downloadEvent = new Effect<EventDBEvent>() {
#Override
public void e(EventDBEvent eventDBEvent) {
...
}
};
I have tried adding org.org.functionaljava:functionaljava-java8:4.32 and org.functionaljava:functionaljava:4.3 IntelliJ recognizes Effect but highlights the first line as error and says:
I have a similar issue in another line:
final ... = new ...(new Effect<Option<Integer>>() {
#Override
public void e(Option<Integer> integerOption) {
}
}, ...);
Type fj.Effect does not have type parameters.
Am I importing the wrong packages?
More generally, is there a way of knowing which packages I should use, based on an existing code?
The Effect class changed so that the arity is in the class name, e.g. Effect0, Effect1, etc., where the arity indicates the number of parameters to the method. You want to use the Effect1 class.
I've implemented a feature in my jUnit tests that takes, for every test case, a fresh copy of a data source. This copy is taken in a folder specific for each test case. The idea is that every test case can start from a clean situation, manipulate it and let it as such after the run. This is often useful when the test fails for analysing the problem.
For now I have to call this feature directly in the test method because I don't know how to retrieve the current test name:
public void testTest1() {
TestHelper th=TestHelper.create("testTest1",subPathToDataSource);
// do the test...
Path dataPath = th.getDataPath();
...
}
I would like to be able to write something like this:
Path dataPath;
#Before
public initTest() {
th=TestHelper.create(SomeJUnitObject.getCurrentTestName(),subPathToDataSource);
...
}
public void testTest1() {
// do the test...
Path dataPath = th.getDataPath();
...
}
Until now I found as answers : "You don't need to know that"... But I do need it !
Is this possible ?
Kind regards
Look at the TestName rule.
You should be able to add in your test class:
#Rule TestName name=new TestName();
And then access it.
(On phone, so can't check versions support/details - might be 4.x only)
Here is an alternative approach; create an abstract class which your "real" test classes inherit.
I have several such examples in my projects and here I will give one, mainly testing for individual JSON Patch operations.
All my test files are JSON, and located under an appropriately named resource directory. The base, abstract class is JsonPatchOperationTest. And here is the full code of AddOperationTest which tests for JSON Patch's add operation:
public final class AddOperationTest
extends JsonPatchOperationTest
{
public AddOperationTest()
throws IOException
{
super("add");
}
}
And that's it! Not even one test method in this class, but of course your implementation may vary.
In your case you probably want to pass the directory name as a constructor argument, or the like.
Sorry if this is a bit of a vague question, however im struggling to find a single solid example on how to do unit testing (isolated testing) with Android...
Here is an example of what i'm wanting to achieve:
// Some class
class Calculator
{
public int Add(int a, int b) { return a+b; }
}
// Simple test
import org.junit.Assert;
import org.junit.Test;
class CalculatorTests
{
#Test
public void should_add_numbers_correctly()
{
Calculator calculator = new Calculator();
int expectedResult = 5 + 5;
int actualResult = calculator.Add(5,5);
Assert.assertEqual(actualResult, expectedResult);
}
}
So one project contains models and logic, then another project contains tests for said library. There is no front end or UI, so I want to do the bare minimum to just be able to test that my methods all work in isolation.
As long as your "library" doesn't contain any references to resources in the Android SDK, there isn't anything more to this than regular unit testing. In your Eclipse workspace, say you have your main project MyAndroidLibProject, you simply create a new Java Project (e.g. MyAndroidLibProjectUnitTests). Inside here, you create ordinary unit tests referring to the Calculator class in your main project (just make sure that your main project is added to the build path of your test project).
You might also find some additional information in a similar question I asked myself earlier, as well as the answer to that question.
Updated with example:
import static org.junit.Assert.*;
import org.junit.Test;
public class SemesterTest
{
#Test
public void aNewSemesterShouldHaveANegativeId()
{
Semester semester = new Semester(2010, SemesterType.FALL);
assertEquals(-1, semester.getInternalId());
}
#Test
public void toStringShouldPrintSemesterTypeAndYear()
{
Semester semester = new Semester(2010, SemesterType.FALL);
assertEquals(SemesterType.FALL + " 2010", semester.toString());
}
#Test
public void equalityShouldOnlyDependOnSemesterTypeAndYear()
{
Semester aSemester = new Semester(2010, SemesterType.FALL);
aSemester.setInternalId(1);
Semester anotherSemester = new Semester(2010, SemesterType.FALL);
anotherSemester.setInternalId(2);
assertEquals(aSemester, anotherSemester);
}
}
The above is a test of my own Semester class (a simple data class representing a semester). Semester is located inside my android project MyMainProject (but the class itself doesn't contain any references to the Android SDK). SemesterTest is located inside my test project MyTestProject (an ordinary Java project), with both MyMainProject and MyTestProject being in the same workspace (and since SemesterTest has the same package name as Semester, I don't need any special import statement to reference Semester either). MyTestProject also has MyMainProject added to its build path (junit.jar is also added to the build path, but this happens automatically, at least in Eclipse I think).
So as you can see, this is nothing but a completely ordinary unit test (JUnit 4, just to have mentioned it). Hope this helps.