views:

42

answers:

1

I am trying to unit test a class that does SAX parsing and creates an object. This class takes a string as a parameter representing the URL of a document on the internet, parses it and then creates an object based on the contents.

I don't want to have the unit tests actually access the network, so I'd like to have a few test xml files to parse. However I can't figure out how to access them from my AndroidTestCases. I don't want to include the test files with the actual application, I want them in the test project (it's a separate project, as is the norm for Android tests from what I could gather - due to the need to have a custom AndroidManifest.xml, for one).

One way would be to put the XML files in the test project's assets directory, I can read them using getContext().getAssets().open(filename) into an InputStream in the test case, but my class expects a URL string. I'd rather not have to provide an InputStream to this class instead of the current URL string. I can test just the parsing by making two methods, one that takes a string and one an Inputstream, and test the second, but how can I then test the one that just takes a string?

How should I design my class and or tests to circumvent this problem?

A: 

You'd want to go with Dependency injection. Based on what I read, you have a method signature like so:

 string -> object // using lambda notation

It sounds like the code you have for getting the contents of the URL exists in the same method you are calling. You should refactor that into a separate object. You can then make a mock object for testing that instead of doing network access, instead does a file operation to your disk with whatever parameters are necessary. In your testing situation, you inject the mock object in place of the real network getter object in your test setup.

The method then doesn't care what object it has, as long as it is returning some text to parse, be that XHTML or XML.

Tejs
What is the difference between that approach and making my class accept an InputStream instead of a string? Isn't that just adding an extra level of indirection?
JRL
Yes. That extra level of abstraction means you can change the underlying code without affecting your main method. You then don't have to pass an InputStream into the method in your normal case, as that isn't what you need to accomplish your task normally.
Tejs