Scala library initialization design - java

I have started an open source Scala project named omniprop. The feature I'm currently exploring is how to allow users of the project to stack JVM-styled property providers. For instance, you may wish to look up properties in java.lang.System, Lift's util.Prop, and Typesafe's Config library. Due to some other constraints/features of omniprop, I need this stack configuration to reside in a known object, so other parts of the library can retrieve properties from this stack.
In order for omniprop to work correctly, this configuration needs to be invoked by the user of the library before any properties are accessed. Hence any project which uses my library will need a bootstrap/initializer which can set up the provider stack. An example of this initial configuration code looks like this:
import com.joescii.omniprop.providers._
PropertyProviders.configure(List(
SystemPropertyProvider,
LiftPropsProvider
))
The challenge I'm facing is with testing in particular. In order for the test code for a project utilizing omniprop to work, it must somehow run the above code before any tests are run. Currently, I don't see a clean way to do this with sbt or any of the testing libraries I am familiar with such as scalatest, scalacheck, or specs2. As it is, one would need to call the above snippet in every test suite, which is certainly not ideal.
Another approach this this problem is what Lift does, in which every project necessarily has a class called bootstrap.liftweb.Boot that the library invokes to set everything up. I find that to be a reasonable approach to a web framework such as Lift, but seems to be too much for a tiny property helper library.
I really have two questions here:
How can I have sbt invoke the above setup code with the correct classloader before all tests run?
More importantly, is this the best design for a library which requires initialization, or is there a better approach?

Using ScalaTest, when I've had to do something similar, I created a trait that extends BeforeAndAfterAll, which I mixed into every suite that needed it.
trait Configure extends Suite with BeforeAndAfterAll {
override def beforeAll() { PropertyProviders.configure(/*...*/); }
override def afterAll() { PropertyProviders.configure(/*...*/); }
}
You just mix it in like any other trait
trait FooSpec extends Spec with Configure {
// ...
}

You could put the initialization code in a trait constructor and have your tests extend from that trait.
Another approach is to have that configuration as the default, and if no configuration is set then it gets used the first time your library code is called. That would cover both testing and non-testing scenarios.
A hybrid approach would be to have your sbt testing configuration set a system property. If that system property is set and no configuration is has been set then the testing config will be used the first time the library code gets called.

Related

Mocking a resource on Android instrumentation test

I want to test the effects of a library call of my program with a real device. This call starts a service, that sends an HTTP request to a server whose URL that is hard-coded in the resources.
I want to verify that the request is sent correctly. So I set up a local HTTP server, but to be able to use it I have to change/override/mock the resource so it points to http://127.0.0.1 instead.
I want to do "end-to-end" testing; in this case it's important that the service makes an actual network request, although locally.
I've tried to override the value by creating a string resource with the same name in androidTest/res/values/strings.xml, but that resource is only visible in the test package, not in the application package.
Using the Instrumentation class only allows me to obtain the Context reference, but there's no way to replace it (or the return value of getResources()) with a mock or something similar.
How can I change a resource value of an Application under test?
You have a couple choices:
Dependency injection
Stubs/mocks
SharedPreferences
Scripts or gradle tasks
Dependency injection
Use a library like RoboGuice or Dapper. Inject an object that handles making the API requests. Then, in your test setup, you can replace the injection modules with testing versions instead. That way your test code runs instead of the original; that code can pass in different strings (either hard-coded or from the test strings.xml) instead.
DI libraries can be expensive to setup: high learning curve and can be performance problems if not used correctly. Or even can introduce hard to debug problems if the scope/lifetime of the objects isn't configured correctly. If testing is the only reason to use DI, it might not be worth it to you if you're not comfortable with a DI container.
Stubs/mocks
Wrap up your calls in something that implements a custom interface you write. Your main implementation then fills in the host URL and calls the API. Then, in tests, use a combination of stubs or mocks on that interface to replace the code that fills in the host URL part.
This is less of an integration test since the stubs or mocks will be replacing parts of the code. But is simpler than setting up a dependency injection framework.
SharedPreferences
Use the Android SharedPreferences system. Have it default to a certain endpoint (production). But allow the app to be started on the testing device, then some dialog or settings to let you change the host URL. Run the tests again and now they point to a different API URL.
Scripts or gradle tasks
Write some script or gradle task to modify the source before it is compiled in certain scenarios.
This can be fairly complicated and might even be too platform or system-dependent if not done right. Will probably be fairly brittle to changes in the system. Might introduce bugs if the wrong command is run to build the final packaged version and the wrong code goes out to the market.
Personal opinion
Which do I recommend? If you and/or your team is familiar with a DI library like RoboGuice or Dapper, I recommend that option. It is the most formal, type-safe and strict solution. It also maintains more of the integrity of the stack to test the whole solution.
If you're not familiar with a good DI library, stubs/mocks and interface wrappers are a good fall back solution. They partly have to be used in the DI solution anyway, and you can write enough tests around them to cover a good majority of the cases you need to test (and are in control of). It is close enough to the DI solution that I would recommend this to everyone who doesn't use DI in the project already.
The SharedPreferences solution works great for switching between staging and production environments for QA and support. However, I wouldn't recommend it for automated tests since the app will most likely be reinstalled/reset so often during development, it would get annoying resetting that URL that often. Also, first runs of tests would probably fail; headless tests on a CI server would fail, etc. (You could default the URL to the localhost, but then you run the risk of accidentally release that default to production sometime.)
I don't recommend scripts or the hacked-up gradle tasks. Too brittle, less clear to other developers that come behind you, and more complicated then they're worth, IMO.
In addition to Jon Adams's solutions, there's a further one:
Override resource in build type
By default, a library module is built in release mode when it's used by another module. The debug mode is only used for testing (unit tests and instrumented tests). Therefore, using the resource overriding it's possible to change the resource value for the instrumentation tests for that library only, and use the original value in the library's users.
This has some caveats though:
Instrumented/integration tests must stay on the library itself, not on the main application package;
The same resource values have to be shared across all tests (unless using product flavors)

How do I compile & instantiate a Java class from source programmatically when it has project dependencies?

This is great, but what if the class in the uncompiled source should inherit from a project specific class (which is already loaded), and has other project dependencies?
As an example, say I want to give users of my software the ability to customize a class at run-time. I have an abstract public class Customizable and a custom class StatusDetails in my project, and lets say the user writes code in a file that looks like this:
import com.somepackage.util.StatusDetails;
public class Test extends Customizable {
public Test(){
System.out.println("Initializing Test");
}
#Override
public StatusDetails getStatus(Object params){
StatusDetails status = new StatusDetails();
// Populate status based on params
return status;
}
}
How could I take that and instantiate it?
First the class will need to be compiled, which means you will have to ship the required JAR files and provide a classpath. To manage this, I highly recommend Apache's Maven, but the learning curve will set you back a bit. The good news is that after your learning curve, you will have a really good tool for building that is fully portable and ideally suited for managing Java projects.
Then you will need to put the output JAR file / classes on the class path of the running program and restart it.
There are other ways of going about it, each with a bit more difficulty. You can avoid the restart by using a classloader, and have the program dynamically load the class in response to a user action.
You can avoid the externalization of the build chain by putting the build chain in the program itself, by calling the compiler tools interface, compiling the program and then using the custom classloader mentioned above to incorporate it into the running program.
The problems with such an approach (as mentioned above) are many. Basically you're giving everyone a huge security hole to exploit. For example, I could "load" code that trashes the filesystem, or opens network sockets for attacking other machines.
I recommend the separate build chain and manual configuration of the load, with a required restart. It may make the user jump through a few more hoops, but it will keep the security holes from being easily exploited.

Where should i put classes only used for development?

I started using dependency injection with roboguice and created an interface like DataProvider. I have an implementation which retrieves the data from some WebServer located in the WebServerDataProvider class. In Order to eliminate the waiting for the webserver i added a DummyDataProvider.
Where would i put such class? I don't like that it is in /src/main/java/my/package/providers/ since it is not real part of the application, but still i need it for development.
Typically you would use such a class in your unit tests. Roboguice works well with Robolectric , which allows you to mock things like http access. If you do that you would put your code in src/test/java/...
You could put it into the main project if you want to use it for fiddling around with the application without bothering the server each time and deactivate it with some constant for deployment, e.g.
if (DEBUG) {
setDataProvider(new MockDataProvider());
}
Proguard should be smart enough to remove this unused class if you remember to reset your variable (you might have to fiddle around with the settings there).

How to reuse test code from open source project

I'm writing a unit test for a custom subclass of org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter<T>
and I need a stub implementation of org.springframework.http.HttpInputMessage. Looking through the Spring unit tests in the SVN repository, I found the class MockHttpInputMessage, which does exactly what I want.
Now, I wonder what is the proper way to reuse this class?
Or is it generally a bad idea, because the class is not meant to be used outside of the Spring unit tests?
I'm not involved in the Spring project, but from the names I would assume that the class is not intended for reuse. Therefore, I would simply take the class in source form and add it to your project test sources.
Of course all this assumes, this is acceptable with respect to licenses.
I would simply copy it to my own repository, and use it to my hearts content. You want it under your own control so that you are not adversely affected by future changes.

Java - keeping multi-version application from splitting codebase

I am writing an application that will ship in several different versions (initially around 10 variations of the code base will exist, and will need to be maintained). Of course, 98% or so of the code will be the same amongst the different systems, and it makes sense to keep the code base intact.
My question is - what would be the preferred way to do this? If I for instance have a class (MyClass) that is different in some versions (MyClassDifferent), and that class is referenced at a couple of places. I would like for that reference to change depending on what version of the application I am compiling, rather than having to split all the classes referring to MyClassDifferent too. Preprocessor macros would be nice, but they bloat the code and afaik there are only proof of concept implementations available?
I am considering something like a factory-pattern, coupled with a configuration file for each application. Does anyone have any tips or pointers?
You are on the right track: Factory patterns, configuration etc.
You could also put the system specific features in separate jar files and then you would only need to include the appropriate jar alongside your core jar file.
I'd second your factory approach and you should have a closer look at maven or ant (depending on what you are using).
You can deploy the different configuration files that determine which classes are used based on parameters/profiles.
Preprocessor makros like C/C++ have are not available directly for java. Although maybe it's possible to emulate this via build scripts. But I'd not go down that road. My suggestion is stick with the factory approach.
fortunately you have several options
1) ServiceLoader (builtin in java6) put your API class like MyClass in a jar, the compile your application against this API. Then put a separate implementation of MyClass in a separate jar with /META-INF/services/com.foo.MyClass. . Then you can maintain several version of your application simply keeping a "distribution" of jars. Your "main" class is just a bunch of ServiceLoader calls
2) same architecture of 1) but replacing META-INF services with Spring or Guice config
3) OSGI
4) your solution
Look up the AbstractFactory design pattern, "Dependency Injection", and "Inversion of Control". Martin Fowler writes about these here.
Briefly, you ship JAR files with all the needed components. For each service point that can be customized, you define an Interface for the service. Then you write one or more implementations of that Interface. To create a service object, you ask an AbstractFactory for it, eg:
AbstractFactory factory = new AbstractFactory();
...
ServiceXYZ s = factory.newServiceXYZ();
s.doThis();
s.doThat();
Inside your AbstractFactory you construct the appropriate ServiceXYZ object using the Java reflection method Class.classForName(), and SomeClassObject.newInstance(). (Doing it this way means you don't have to have the ServiceXYZ class in the jar files unless it makes sense. You can also build the objects normally.)
The actual class names are read in from a properties file unique to each site.
You can roll your own solution easily enough, or use a framework like Spring, Guice, or Pico.

Categories