How can I get context of test application itself in ApplicationTestCase<MyApp>? - java

How can I get context of test application itself in ApplicationTestCase<MyApp>?
I use test application's resources to store some reference data, but I cannot acquire it's context, as far as I see.
I'm trying to do the following:
referenceContents = readRawTextFile(
getSystemContext(),
//test application's res namespace is myApp.test.*
myApp.test.R.raw.reference_file);
where readRawTextFile is simple text reader routine, but the data I get is wrong.

If you need the context of the application you're testing (i.e. MyApp) then this is how you do it:
public class MyAppTest extends ApplicationTestCase<MyApp> {
public MyAppTest () {
super(MyApp.class);
}
public MyAppTest (Class<MyApp> applicationClass) {
super(applicationClass);
}
#Override
protected void setUp() throws Exception {
super.setUp();
createApplication();
}
public void testMyApp() throws Exception {
// Retrieves a file in the res/xml folder named test.xml
XmlPullParser xml = getContext().getResources().getXml(R.xml.test);
assertNull(xml);
}
}
As you can see, you get the context of your application under test using:
getContext()
in your test case.
However if you have two separate projects: One is your application and one is your test project and you need the context of the testproject, then the only choice you have is to extend InstrumentationTestCase instead of ApplicationTestCase - however, this means that you won't be able to obtain a context of the application project, but only a context of your test project.

Related

Springboot, how to show Banner programmtically at start, again

If a springboot application starts, a logo/banner is shown.
I took my own, colored banner in a banner.txt file. It is shown at starts, all is fine.
But I want to repeat my banner after successfull or not successfull start as last startup message. Like: Banner + "runs" or Banner + "do not run".
Something like this:
public static void main( String[] args )
{
try {
SpringApplication.run( ControllerUndMain.class, args );
showLogo();
System.out.println('runs')
} catch(Exception e){
showLogo();
System.out.println('not working')
}
}
This helps our admins and devops to see, that startup phase ends and if applications run or not.
Question: How to show banner programmatically?
I could not found any straight way of doing it. I did a drive into spring code base and found way of doing that. I've tested in my project and its working fine.
Note: I've copied some of the class which are used by spring to print banner. I don't see any issue on reusing in our code base.
Here is a entire code....
Main class which runs springboot application and I've created method to print banner.
public class DemoApplication {
#Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(DemoApplication.class);
ConfigurableApplicationContext test = app.run(args);
DemoApplication application = new DemoApplication();
application.printBanner(app, test);
}
public void printBanner(SpringApplication app, ConfigurableApplicationContext test) {
ResourceLoader resourceLoader = (app.getResourceLoader() != null ? app.getResourceLoader()
: new DefaultResourceLoader(app.getClassLoader()));
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, null);
Banner banner = bannerPrinter.print(DemoApplication.class, test.getEnvironment());
banner.printBanner(test.getEnvironment(), DemoApplication.class, System.out);
}
}
After adding above code base just copy SpringApplicationBannerPrinter and SpringBootBanner class(You will get those form Spring code base) in your project and run.
Note: 1) I've tested before posing answer here.
2) To make answer short, I've not pasted SpringApplicationBannerPrinter and SpringBootBanner. Let me know if you want me to paste those class in answer
#SpringBootApplication
public class SimpleDemoApplication {
public static void main(String[] args) {
final SpringApplication app;
final ConfigurableApplicationContext context;
app = new SpringApplication(SimpleDemoApplication.class);
context = app.run(args);
print(context);
}
public static void print(ConfigurableApplicationContext context) {
Banner banner = context.getBean(Banner.class);
banner.printBanner(context.getEnvironment(), SimpleDemoApplication.class, System.out);
}
}
Just inject or get over context.getBean the org.springframework.boot.Banner.class. This helps for the good case, if all is fine and context is up.
I dont have a solution for the bad case, if context dont running.

Create a TestServer with an already started FakeApplication

I've started integrating in some Selenium tests into the testing framework in Play. I have a class in which I define a lot of special config settings for a FakeApplication, then create that FakeApplication using:
public abstract class FakeApplicationTest {
public static FakeApplication createFakeApp() {
// grab the main application.conf file that is used to start up the Play application
Config config = ConfigFactory.parseFile(new File("conf/application.conf"));
// resolve all variables within this config file with other variables within itself
config = ConfigFactory.load(config);
// create a Configuration object out of this and then turn it into a Map to be modified
Configuration configuration = new Configuration(config);
Map<String, Object> fakeApplicationConf = Maps.newHashMap(configuration.asMap());
...
// CUSTOM CONFIG THINGS HERE
...
return Helpers.fakeApplication(fakeApplicationConf);
}
}
What I would like to be able to do, is use this FakeApplication, start it in a #Before method (using JUnit 4), and then pass that already running FakeApplication to the TestServer which is needed to run the Selenium tests.
public class Checkout extends FluentTest {
public WebDriver webDriver = new FirefoxDriver();
...
public FakeApplication app;
#Before
public void beforeTest() {
app = FakeApplicationTest.createFakeApp();
Helpers.start(app);
FakeApplicationTest.createCleanDb();
...
}
#Test
public void testReviewPage()
running(testServer(3333, app), webDriver, browser -> {
...
}
}
}
What seems to happen when I do this though, is that the existing, running FakeApplication gets ignored/tossed and a new FakeApplication is created and started which is not setup with my custom fakeApplicationConf Map... or, it's stopping the app and restarting it but goes back to only use my default application.conf.
Any ideas on why this is? or if I can somehow accomplish this in a different way?

Is there any way to test classes that access ContentResolver with JUnit? Or do I have to use Robolectric?

I have a test class like this:
public class PostRepositoryTest extends AndroidTestCase {
Context context;
#Before
public void setUp() throws Exception {
context = new Application();
}
#Test
public void testFindAll() {
PostRepository postRepository = PostRepository.get(context);
List<Post> all = postRepository.findAll();
assertEquals(0, all.size());
}
}
findAll method just uses a ContentResolver to return results from a ContentResolver.
public List<Post> findAll() {
Cursor c = new PostSelection().query(context.getContentResolver());
return listFromCursor(c);
}
Before trying this way... I was doing this by using AndroidInstrumentationTestCase2 and launching an activity to check all of those things, but I want to avoid that.
I'd like to do this as an unit test. Is it possible?
It depends whether you want to run this test case on a device or not. Go for Robolectric if you want to run it on local JVM instead of running on device.
If you want to run on device without AndroidInstrumentationTestCase2, then you can use AndroidJUnitRunner. Its based on Junit4 specification.
Read the link here:
https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html
See the code samples for basic idea:
https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicUnitAndroidTest
If you setup your test suite according to the above link then you don't need to extend any class or launch an activity. You can get context object using the code:
InstrumentationRegistry.getTargetContext();
or
InstrumentationRegistry.getContext();

Building a Spring ConfigurationRetriever to load beans from spring context file for a command line program. How to use #Autowired in this clas?

I am building a command-line program in java with the spring framework. Based on the arguments passed into the command-line program the relevant beans would need to be loaded and executed. So I rely on this ConfigurationRetriever class I've shown below. But I'm having to do a get bean everywhere in the ConfigurationRetriever (it works fine with calling getBean like I've shown in the code). Ideally I would like to use #Autowired. How can I do that?
Thank you in advance!
public class ConfigurationRetriever {
private ApplicationContext context;
public ConfigurationRetriever() {
context = new ClassPathXmlApplicationContext("beans-service.xml");
}
public ServiceNameRunProperties getSearchIndexServices(String service_name) {
ServiceNameRunPropertiesDao dao = (ServiceNameRunPropertiesDao) context
.getBean("serviceNameRunPropertiesDaoImpl");
ServiceNameRunProperties serviceNameRunProperties = new ServiceNameRunProperties();
serviceNameRunProperties = dao
.getServiceRunPropertiesByName(service_name);
return serviceNameRunProperties;
}
public String getQueryExecutorService() {
QueryExecutorService queryExecutorService = (QueryExecutorService) context
.getBean("queryExecutorImpl");
return queryExecutorService.executeQuery();
}
}

Unit Testing gwt-dispatch

I'm trying to write some unit tests for a gwt-dispatch service with JUnit. I'm getting the following error when stepping through the test with my debugger:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
I'm going to simplify the code a bit here -- hopefully I'm not stripping out anything necessary.
import junit.framework.TestCase;
import net.customware.gwt.dispatch.client.standard.StandardDispatchService;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.ServletModule;
...
public class LoggedInServiceTest extends TestCase {
Injector i;
StandardDispatchService service;
protected com.google.inject.Injector getInjector() {
return Guice.createInjector(new ServletModule(),
new TestServletModule(),
new ActionsHandlerModule(),
new TestDispatchModule(),
new OpenIdGuiceModule());
}
public void setUp() throws Exception {
i = getInjector();
service = i.getInstance(StandardDispatchService.class);
}
public void testNotLoggedIn() {
try {
GetProjectsResult result = (GetProjectsResult) service.execute(new GetProjectsAction());
result.getSizeOfResult();
} catch (Exception e) {
fail();
}
}
}
The service request is indeed supposed to be going through a GuiceFilter, and it looks like that filter is not being set.
Any ideas on what other setup needs to be done to register the filter?
The problem is just what it states. You are trying to access a scoped object, but you are not currently in the scope. Most likely, your test is asking the injector for a RequestScoped object or an object that has a RequestScoped object in the injection dependency tree, but the test didn't do anything to enter the scope.
Binding the GuiceFilter in the test doesn't help, because your test isn't trying to send an HttpServletRequest through GuiceFilter to a servlet.
The best option would be to unit test your code. Create your classes in isolation, injecting mocks.
Assuming you want to do some kind of integration test, you have three options:
Have your test install a test module that called bindScope(RequestScoped.class, new FakeScope). The FakeScope class would implement Scope and have methods to enter and exit the scope. You may have to "seed" the scope with fake implementations of objects you depend on. See the Guice CustomScopes wiki page. This is the best option for integration tests, IMHO
Use ServletScopes.scopeRequest (Javadoc) to run part of the test code inside of a simulated request scope. This gets a bit ugly since you need to pass a Callable.
Do a full end-to-end test. Start your server and send it requests using Selenium. It's really hard to get good coverage this way, so I would leave this to things that you really need a browser to test.
Things might get a bit messy if the class you are testing depends indirectly on HttpServletRequest or HttpServletResponse. These classes can be challenging to setup correctly. Most of your classes should not depend on the servlet classes directly or indirectly. If that is not the case, you are either doing something wrong or you need to find a good action framework that allows you have most of your code not depend on these classes.
Here's an example of approach 1, using SimpleScope from the Guice CustomScopes wiki page:
public class LoggedInServiceTest extends TestCase {
private final Provider<StandardDispatchService> serviceProvider;
private final SimpleScope fakeRequestScope = new SimpleScope();
private final HttpServletRequest request = new FakeHttpServletRequest();
protected Injector createInjector() {
return Guice.createInjector(new FakeRequestScopeModule(),
new LoggedInServiceModule();
}
#Override
protected void setUp() throws Exception {
super.setUp();
Injector injector = createInjector();
scope.enter();
serviceProvider = injector.getProvider(StandardDispatchService.class);
}
#Override
protected void tearDown() throws Exception {
fakeRequestScope.exit()
super.tearDown();
}
public void testNotLoggedIn() {
fakeRequestScope.enter();
// fill in values of request
fakeRequestScope.seed(FakeHttpServletRequest.class, request);
StandardDispatchService service = serviceProvider.get();
GetProjectsAction action = new GetProjectsAction();
try {
service.execute(action);
fail();
} catch (NotLoggedInException expected) {
}
}
private class FakeRequestScopeModule extends AbstractModule() {
#Override
protected void configure() {
bind(RequestScoped.class, fakeRequestScope);
bind(HttpServletRequest.class)
.to(FakeHttpServletRequest.class)
.in(RequestScoped.class)
}
}
}
Write an AppSession interface and two implementations: HttpAppSession and MockAppSession.
Make your server-side handlers depend on AppSession and not on HttpSession directly.
Use Guice to inject HttpSession into HttpAppSession. That's the one you'll use in production, and for actually running your app. within a real servlet container.
The MockAppSession should not depend on HttpSession, nor HttpServletRequest, nor any other Guice Http scope. That's the one you'll use during testing.
Now, your Guice module should inject an AppSession implementation as follows:
bind(AppSession.class).to(MockAppSession.class)
bind(MockAppSession.class).in(Singleton.class)
That'll sort you out.

Categories