Cannot access test resource from production class - java

I have the following class which I want to unit test:
class PropsProvider {
String propsfileLocation;
void init() {
Path path = getPropsPath();
loadPropertiesFromPath(path);
}
private Path getPropsPath() throws URISyntaxException {
URI fileUri = new URI(propsfileLocation);
return Paths.get(fileUri); // << failure here
}
// ...
}
I am unit testing the above class and I keep getting a failure on the line Paths.get(fileUri). I get an IllegalArgumentException. I am passing in a relative path from my unit test, which is src/test/resources/app.properties. I believe this is happening because I haven't included the prefix file:. The unit test resides in the same package as the above class albeit in the /src/test/java folder. How can I fix this?

You can get the path of any resource using Google's Guava library.
URL myFileLocation=Resources.getResource("myFile.txt");
For more look here.
http://google.github.io/guava/releases/22.0/api/docs/com/google/common/io/Resources.html#getResource-java.lang.Class-java.lang.String-

Related

How do I include a resource file in Java project to be used with just new File()?

I'm writing a UDF for Pig using Java. It works fine but Pig doesn't give me options to separate environment. What my Pig script is doing is to get Geo location from IP address.
Here's my code on the Geo location part.
private static final String GEO_DB = "GeoLite2-City.mmdb";
private static final String GEO_FILE = "/geo/" + GEO_DB;
public Map<String, Object> geoData(String ipStr) {
Map<String, Object> geoMap = new HashMap<String, Object>();
DatabaseReader reader = new DatabaseReader.Builder(new File(GEO_DB)).build();
// other stuff
}
GeoLite2-City.mmdb exists in HDFS that's why I can refer from absolute path using /geo/GeoLite2-City.mmdb.
However, I can't do that from my JUnit test or I have to create /geo/GeoLite2-City.mmdb on my local machine and Jenkins which is not ideal. I'm trying to figure out a way to make my test passed while using new File(GEO_DB) and not
getClass().getResourceAsStream('./geo/GeoLite2-City.mmdb') because
getClass().getResourceAsStream('./geo/GeoLite2-City.mmdb')
Doesn't work in Hadoop.
And if I run Junit test it would fail because I don't have /geo/GeoLite2-City.mmdb on my local machine.
Is there anyway I can overcome this? I just want my tests to pass without changing the code to be using getClass().getResourceAsStream and I can't if/else around that because Pig doesn't give me a way to pass in parameter or maybe I'm missing something.
And this is my JUnit test
#Test
#Ignore
public void shouldGetGeoData() throws Exception {
String ipTest = "128.101.101.101";
Map<String, Object> geoJson = new LogLine2Json().geoData(ipTest);
assertThat(geoJson.get("lLa").toString(), is(equalTo("44.9759")));
assertThat(geoJson.get("lLo").toString(), is(equalTo("-93.2166")));
}
which it works if I read the database file from resource folder. That's why I have #Ignore
Besides, your whole code looks pretty un-testable.
Every time when you directly call new in your production code, you prevent dependency injection; and thereby you make it much harder to test your code.
The point is to not call new File() within your production code.
Instead, you could use a factory that gives you a "ready to use" DatabaseReader object. Then you can test your factory to do the right thing; and you can mock that factory when testing this code (to return a mocked database reader).
So, that one file instance is just the top of your "testing problems" here.
Honestly: don't write production code first. Do TDD: write test cases first; and you will quickly learn that such production code that you are presenting here is really hard to test. And when you apply TDD, you start from "test perspective", and you will create production code that is really testable.
You have to make the file location configurable. E.g. inject it via constructor. E.g. you could create a non-default constructor for testing only.
public class LogLine2Json {
private static final String DEFAULT_GEO_DB = "GeoLite2-City.mmdb";
private static final String DEFAULT_GEO_FILE = "/geo/" + GEO_DB;
private final String geoFile;
public LogLine2Json() {
this(DEFAULT_GEO_FILE);
}
LogLine2Json(String geoFile) {
this.geoFile = geoFile;
}
public Map<String, Object> geoData(String ipStr) {
Map<String, Object> geoMap = new HashMap<String, Object>();
File file = new File(geoFile);
DatabaseReader reader = new DatabaseReader.Builder(file).build();
// other stuff
}
}
Now you can create a file from the resource and use this file in your test.
public class LogLine2JsonTest {
#Rule
public final TemporaryFolder folder = new TemporaryFolder();
#Test
public void shouldGetGeoData() throws Exception {
File dbFile = copyResourceToFile("/geo/GeoLite2-City.mmdb");
String ipTest = "128.101.101.101";
LogLine2Json logLine2Json = new LogLine2Json(dbFile.getAbsolutePath())
Map<String, Object> geoJson = logLine2Json.geoData(ipTest);
assertThat(geoJson.get("lLa").toString(), is(equalTo("44.9759")));
assertThat(geoJson.get("lLo").toString(), is(equalTo("-93.2166")));
}
private File copyResourceToFile(String name) throws IOException {
InputStream resource = getClass().getResourceAsStream(name);
File file = folder.newFile();
Files.copy(resource, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
return file;
}
}
TemporaryFolder is a JUnit rule that deletes every file that is created during test afterwards.
You may modify the asserts by using the hasToString matcher. This will give you more detailed information in case of a failing test. (And you have to read/write less code.)
assertThat(geoJson.get("lLa"), hasToString("44.9759"));
assertThat(geoJson.get("lLo"), hasToString("-93.2166"));
You don't. Your question embodies a contradiction in terms. Resources are not files and do not live in the file system. You can either distribute the file separately from the JAR and use it as a File or include it in the JAR and use it as a resource. Not both. You have to make up your mind.

ClassNotFoundException for stub while activating a remote object

public void Test {
String location = xyz; //location of the class file for the stub
ActivationDesc desc = new ActivationDesc( "TestObjectImpl", location, null);
ActivationID id = ActivationGroup.getSystem().registerObject(desc);
TestObject to = (TestObject)id.activate(true);
}
On running the above code, I get ClassNotFoundException for TestObjectImpl_stub . I looked around the web and found two possible workarounds:
Specify the path of the class files in CLASSPATH variable.
While executing the test, mention java.rmi.server.codebase=location along with the java command, location being the location of the class files.
Which of the above method is more appropriate? Is there a better solution for this?

Looking for a file doesn't work without "file:"

I'm testing web-flow, and i need to found xml file that contains application's flow. But I really don't understand why is necessary put file: before the path, why is this necessary?
declaration path:
protected static final String ARREL_FLOWS = "file:src/main/webapp/WEB-INF/flow/";
protected static final String FLOW_CONSULTA_DEUTE = ARREL_FLOWS +"consultaDeutes/consultaDeutes.xml";
Code to test the path flow:
#Test
#Override
protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) {
FlowDefinitionResource resource = resourceFactory.createResource(FLOW_CONSULTA_DEUTE);
Assert.assertNotNull(resource);
return resource;
}
this is py project estrucuture:
ty.
OK I find out why! i feel like a monkey..
well:
If don't wanna put the word file: i necessary use the method:
resource = resourceFactory.createFileResource(getPathRecursFlowProvatura());
not
FlowDefinitionResource resource = resourceFactory.createResource(FLOW_CONSULTA_DEUTE);

How to run the servlet test by using HttpUnit servlet runner? Problems in Starting up with ServletUnit?

I was planning to unit test my Servlet through ServletUnit and ran across some problems :
- As a starting point, we are supposed to create a ServletRunner object. One of the constructors expects File object with web.xml file. I provide the full path of my web.xml file but somehow it ignores the path provided and searches at the top level folder. The code-snippet and error message is below:
Code Snippet
ServletRunner sr = new ServletRunner(new File("* C:/eclipse-workspaces/pocs/lms-csd/src/main/webapp/WEB-INF/web.xml*"));
ServletUnitClient sc = sr.newClient();
WebRequest request = new PostMethodWebRequest("path to be specified" ); request.setParameter( "userId", "test" );
request.setParameter( "password", "csd" );
WebResponse response = sc.getResponse(request);
String text = response.getText();
Assert.assertTrue(text.contains("Welcome to Leave Management System"));
stack trace
com.meterware.httpunit.HttpInternalErrorException:
Error on HTTP request: 500 org.apache.jasper.JasperException: java.io.FileNotFoundException: * C:\eclipse-workspaces\pocs\lms-csd\WEB-INF\web.xml*
(The system cannot find the path specified)
[http://localhost/login] - Why does the system keep on looking at the folder structure to be .../WEB-INF/web.xml.
Mine is a maven project and I would not like to change the structure of the project to adapt this way. How can I make ServletRunner class to read from a specified folder ? - In the Servlet code,
I use the following code :
String result = null if (someCondition) result = "/welcome.jsp"; } else { logger.warn("Password Validation failed"); request.setAttribute("failedlogin", new Boolean(true)); result = "/index.jsp"; } } RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher(result); requestDispatcher.forward(request, response);
Again ServletUnit expects welcome.jsp to be at root foler, though jsp files are present at .../src/main/webapp/ folder. Again how can ServletUnit be told about the target folder location ?
Many thanks in advance.
Best Regards
M.SuriNaidu
This is the sort of thing I do. This is a facsimile of the base class of my servlet tests. In this case I pass the relative path of the web.xml file as it exists in my source tree. I run these tests from ant and eclipse.
abstract public class ServletTestCase {
protected ServletRunner m_runner;
protected ServletUnitClient m_client;
protected String m_userAgent = "something/1.0";
#Override
protected void setUp() throws Exception {
super.setUp();
initHttpUnit();
}
#Override
protected void tearDown() throws Exception {
shutdownHttpUnit();
super.tearDown();
}
protected void initHttpUnit() throws IOException, SAXException {
shutdownHttpUnit();
// We are expecting UTF-8 character handling in URLs, make it the default
HttpUnitOptions.setDefaultCharacterSet("UTF-8");
// Find the servlet's web.xml file and use it to init servletunit
File file = new File("tests/web.xml"));
m_runner = new ServletRunner(file);
m_client = m_runner.newClient();
m_client.getClientProperties().setUserAgent(m_userAgent);
}
protected void shutdownHttpUnit() {
if (m_runner != null) {
m_runner.shutDown();
}
m_client = null;
m_runner = null;
}
}

Couldn't get resource paths for class path resource

all, I am puzzled about the struts2 action unit test
import org.apache.struts2.StrutsSpringTestCase;
import org.junit.Test;
import com.opensymphony.xwork2.ActionProxy;
public class TestLoginAction extends StrutsSpringTestCase {
#Test
public void testCheck() throws Exception {
ActionProxy proxy = null;
LoginAction test = null;
request.setParameter("username", "admin");
proxy = getActionProxy("/checkLogin");
test = (LoginAction) proxy.getAction();
String result = proxy.execute();
assertEquals("error", result);
assertEquals("admin", test.getUsername());
}
}
It throw the warnings and exceptions:
Couldn't get resource paths for class path resource [WEB-INF/jsp/]
java.io.FileNotFoundException: class path resource [WEB-INF/jsp/] cannot be resolved to URL because it does not exist
StrutsSpringTestCase is expecting the Spring configuration to be loaded from classpath:applicationContext.xml. You can override this behavior by adding this to your test action:
#Override
public String getContextLocations() {
return "path/to/your/TestLoginAction-context.xml";
}
the reason of throwing the exception has been found,
I use struts-convention to find my action classes,but
,this configuration is the base search path of jsp files,so of course the convention can't recognize the path as java class path,I will provide the two workaround here:
you can modify the configuration value "/WEB-INF/jsp" to the existing class path,such as "com.foo.bar" to make the convention resolve class path smoothly
rewrite the MockServletContext and swallow the throwing Exception
public Set getResourcePaths(String path) {
....
}
You may add a line as follows to struts.xml to work around it.
<constant name="struts.convention.result.path" value="/your/path" />

Categories

Resources