I am trying to write the Junit test cases for the class that reads Properties file Here is my code:
public class PropertiesRetreiver {
private String foo = "";
private String foo1 = "";
private static String PROPERTIES_PATH ="data.properties";
public PropertiesRetreiver() throws IOException {
InputStream in = this.getClass().getResourceAsStream(PROPERTIES_PATH);
Properties properties = new Properties();
properties.load(in);
foo = properties.getProperty("foo");
foo1 = properties.getProperty("foo1");
}
public String getfoo() {
return foo;
}
public String getfoo1() {
return foo1;
}
}
Can anyone give me idea about test case scenario I can mock and test? Thank you very much for your help.
Your class actually make 2 things : it loads a property file, and stores some specific properties.
For testing purpose, you could (should?) concentrate on one aspect at a time only, either by splitting these 2 roles in different class (a PropertiesLoader and PropertyStore for example) or at least allow for some injection in your class.
Removing unecessary code from the constructor is always a good idea if you want to properly test your classes :)
ex:
public class PropertiesRetreiver {
private String foo = "";
private String foo1 = "";
private static String PROPERTIES_PATH ="data.properties";
public PropertiesRetreiver() {
}
public void loadProperties() throws IOException {
loadProperties(PROPERTIES_PATH);
}
public void loadProperties(String path) throws IOException {
InputStream in = this.getClass().getResourceAsStream(path);
Properties properties = new Properties();
properties.load(in);
loadProperties(properties);
}
public void loadProperties(Properties properties) {
foo = properties.getProperty("foo");
foo1 = properties.getProperty("foo1");
}
public String getfoo() { return foo; }
public String getfoo1() { return foo1; }
}
This code will be much more easy to test since you can focus on each aspect of the properties load/retreival
Related
New in JUnit here. I am using JUnit 4 with Mockito. How do I write junit for "if" condition?
Note: I am trying to cover inside the if statement when question is not null. Hopefully my question makes sense.
public class MyClass{
private HttpServletRequest request;
private A a;
private B b;
public void go(String something, String s){
MyQuestion question = Exam.getSubject().getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
// getMarks I do have catching an exception
Here is the snippet:
public class MarksClass{
Public MyQuestion getMarks(long idA, long IdB, String s){
try{
//some code
}catch(Exception e){
throw new SomeException("exception" + e);
}
}
}
Assuming, "getSubject" returns a field with name "subject".
final HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
ReflectionTestUtils.setField(myClass, "request", mockedRequest);
final MarksClass mockedMarksClass = Mockito.mock(MarksClass.class);
final MyQuestion mockedResult = Mockito.mock(MyQuestion.class);
Mockito.when(mockedMarksClass.getMarks(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString()).thenReturn(mockedResult);
ReflectionTestUtils.setField(myClass, "subject", mockedMarksClass);
//... rest of the test
Design your class in such a way that testing becomes easy. Or change the design so that it can be tested more easily.
Having global singletons makes testing difficult, if not impossible. The general way forward is to have a class injected with all its external dependencies (DI, dependency injection) or pass the dependencies as arguments to the method.
public class MyClass {
private HttpServletRequest request;
private A a;
private B b;
private final Supplier<Subject> subjectFactory;
public MyClass(final Supplier<Subject> subjectFactory) {
this.subjectFactory = subjectFactory;
}
public void go(String something, String s){
final MyQuestion question = subjectFactory.get().getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
Then in your real code, initialize the class with a method reference to the method on your singleton:
final MyClass myClass = new MyClass(Exam::getSubject);
And in your test inject a test double:
new MyClass(() -> new Subject() {
#Override
public MyQuestion getMarks(…) {
return null;
}
);
Of course, nothing is prevent you from changing the Supplier<Subject> to a Supplier<MyQuestion>, Function<String, MyQuestion>, or a custom interface; and then replacing this with a test double.
#FunctionalInterface
public interface Grader {
MyQuestion getMarks(String idA, String idB, String something);
}
public class MyClass {
private HttpServletRequest request;
private A a;
private B b;
private final Grader grader;
public MyClass(final Grader grader) {
this.grader = grader;
}
public void go(String something, String s){
final MyQuestion question = grader.getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
And then again in your production code vs your test code:
final MyClass production = new MyClass(Exam.getSubject()::getMarks);
final MyClass underTest = new MyClass((a, b, something) -> null);
Providing different implementations of this interface can make your code a bit more expressive:
public class ExamSubjectGrader implements Grader {
#Override
public MyQuestion getMarks(String idA, String idB, String something) {
return Exam.getSubject().getMarks(idA, idB, something);
}
}
public class NullGrader implements Grader {
#Override
public MyQuestion getMarks(String idA, String idB, String something) {
return null;
}
}
MyClass production = new MyClass(new ExamSubjectGrader());
MyClass underTest = new MyClass(new NullGrader());
(both of those are actually singletons, but they could have their own dependencies or state).
And as you can see: you don't even need a heavy mocking library such as Mockito. Good ol' Java can do that just fine.
Find more details in the question Why is my class not using my mock in unit test?
My overall goal is to load properties from a properties file and then inject those properties into my objects. I would also like to use those properties to instantiate certain singleton classes using Guice. My singleton class looks like this:
public class MainStore(){
private String hostname;
#Inject
public void setHostname(#Named("hostname") String hostname){
this.hostname = hostname;
}
public MainStore(){
System.out.println(hostname);
}
}
I'm trying to instantiate a singleton using this provider:
public class MainStoreProvider implements Provider<MainStore> {
#Override
public MainStore get(){
MainStore mainStore = new MainStore();
return mainStore;
}
}
My configurationModule is a module that loads a configuration from a property file specified at runtime:
public class ConfigurationModule extends AbstractModule {
#Override
protected void configure(){
Properties properties = loadProperties();
Names.bindProperties(binder(), properties);
}
private static Properties loadProperties() {
String resourceFileName = "example.properties";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(resourceFileName);
Properties properties = new Properties();
properties.load(inputStream);
return properties;
}
}
And my example.properties files contains:
hostname = testHostName
Then when I need the MainStore singleton I'm using:
Injector injector = Guice.createInjector(new ConfigurationModule());
MainStoreProvider mainStoreProvider = injector.getInstance(MainStoreProvider.class);
MainStore mainStore = mainStoreProvider.get(); //MainClass singleton
Is this the right path to go down? Should I be doing this a completely different way? Why does my MainStore not print out the correct hostname?
I have written up a small example that demonstrates how to bind a Singleton, how to inject a property and so on.
public class TestModule extends AbstractModule {
#Override
protected void configure() {
Properties p = new Properties();
p.setProperty("my.test.string", "Some String"); // works with boolean, int, double ....
Names.bindProperties(binder(),p);
bind(X.class).to(Test.class).in(Singleton.class); // This is now a guice managed singleton
}
public interface X {
}
public static class Test implements X {
private String test;
#Inject
public Test(#Named("my.test.string") String test) {
this.test = test;
System.out.println(this.test);
}
public String getTest() {
return test;
}
}
public static void main(String[] args) {
Injector createInjector = Guice.createInjector(new TestModule());
Test instance = createInjector.getInstance(Test.class);
}
}
The configure method is now responsible to tell guice that my Test class is a singleton.
It prints the correct hostname (property test) because I inject the constructor and set the property.
You can do this with a provider as well, however you will then have to create your objects manually. In my case, this would look like this:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
public TestProvider(#Named("my.test.string") String test) {
this.test = test;
}
#Override
public X get() {
if(instance == null) {
instance = new Test(test);
}
return instance;
}
}
Binding will then look like this:
bind(X.class).toProvider(TestProvider.class);
Is this what you wanted?
Cheers,
Artur
Edit:
I did some test and found this to note:
You can bind a provider as a singleton:
bind(X.class).toProvider(TestProvider.class).in(Singleton.class);
That way you do not need to handle singleton creation yourself:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
#Inject
public TestProvider(#Named("my.test.string") String test) {
this.test = test;
}
#Override
public X get() {
return instance;
}
}
The above code will create singletons of the object X.
Consider the following code:
#Tested
CodeToTest codeToTest;
#Injectable
Injected injected;
#Test
public void test() {
new Expectations() {{ ... }}
assertThat(codeToTest.memberVariable).isEqualTo("x");
}
//
public class CodeToTest { public CodeToTest(Injected injected) { memberVariable = injected.getProperty("x") } }
I want to test CodeToTest. CodeToTest needs Injected to be injected into it's constructor. How do I set a property such as injected.setProperty("x") so that it is available for access in CodeToTest?
The test at hand should be covering a specific method of CodeToTest; the constructor should have its own tests like your test does. So for example, if the constructor is setting a field according to what gets passed in, like this:
public class Bar {
public int getValue() {
return 8675309;
}
}
public class Foo {
public String field = null;
public Foo(Bar b) {
this.field = "" + b.getValue();
}
public String getField() {
return this.field;
}
public char getFirstChar() {
return getField().charAt(0);
}
}
Here I am setting a String field according to an int found in a Bar that was passed into the constructor. I wish to unit test my getFirstChar() method ...
#Tested Foo foo;
#Injectable Bar bar;
#Test
public void test() throws Exception {
// ...
}
Now, as you point out, in this case my field has already been set before test() even starts. So I have two choices here: Firstly, since I am pulling out the field based on its getter, I can partially mock my class being tested:
#Test
public void test() throws Exception {
new Expectations(foo) {{
foo.getField(); result = "24601";
}};
char c = foo.getFirstChar();
assertThat(c, is('2'));
}
OR, if you don't want to do this or if you are doing direct field access rather than via getter, you can use Deencapsulation (part of JMockit) to set the internal field and then test:
#Test
public void test() throws Exception {
Deencapsulation.setField(foo, "field", "24601");
char c = foo.getFirstChar();
assertThat(c, is('2'));
}
And of course, I test my constructor separately:
#Test
public void testConstructor() throws Exception {
new Expectations() {{
bar.getValue(); result = 24601;
}};
Foo foo2 = new Foo(bar);
String fieldValue = foo2.getField(); // or use Deencapsulation
assertThat(fieldValue, is("24601"));
}
Hope this helps, and good luck!
I've learnt how to unit test basic things within Android, e.g. getting and setting of methods as below etc. but when it comes to the more complex stuff like my actual code below, I'm a little flummoxed at what to do.
public class SurveyTest extends TestCase {
private Survey survey;
protected void setUp() throws Exception {
super.setUp();
survey = new Survey();
}
public void testGetId() {
long expected = (long) Math.random();
survey.setId(expected);
long actual = survey.getId();
Assert.assertEquals(expected, actual);
}
public void testGetTitle() {
String expected = "surveytitle";
survey.setTitle(expected);
String actual = survey.getTitle();
Assert.assertEquals(expected, actual);
}
My small code that I'm stuck on how to Junit Test in the format as above:
public abstract class PrimaryModel extends Observable implements Serializable{
protected void notifyModelChange()
{
setChanged();
notifyObservers();
}
public String serialize() throws IOException
{
ObjectOutputStream objOutStream = null;
ByteArrayOutputStream bytArrOutStream = null;
try
{
bytArrOutStream = new ByteArrayOutputStream();
objOutStream = new ObjectOutputStream(bytArrOutStream);
objOutStream.writeObject(this);
}
finally
{
String main = new String(bytArrOutStream.toByteArray());
objOutStream.close();
bytArrOutStream.close();
return main;
}
}
public static PrimaryModel deserialize(String data) throws IOException, ClassNotFoundException
{
ObjectInputStream objInputStream = new ObjectInputStream(new ByteArrayInputStream(data.getBytes()));
PrimaryModel obj = (PrimaryModel) objInputStream.readObject();
objInputStream.close();
return obj;
}
}
Something like a serialize/deserialize pair of methods is generally easily tested. You need to know that a round trip returns an object which is equivalent to the original.
private static class PrimaryModelSubclass extends PrimaryModel {
/* add methods as needed */
}
final PrimaryModel original = new PrimaryModelSubclass(7, "some string", 43.7);
final PrimaryModel wellTravelled = PrimaryModel.deserialize(original.serialize());
assertEquals(original, wellTravelled);
You will need hashCode and equals methods to be correctly defined as well.
Updated in response to comment
I have method for which I need to create a JUnit test:
public class MyClass {
private String file1;
private String file2;
public void myMethodSpaceCheck(){
if (new File(file1).size() > new File(file2).size() {
throw new Exception .....
}
}
}
Is it possible to use Mockito to create that JUnit test?
When dealing with files in Java, my preferred option is to go with Apache VFS, as I can then treat them as any other POJO. Obviously, that's a lot of work when you are already stuck with the File API.
Another option is to forget Mockito entirely and write those files on the system. I usually avoid that, as it sometimes make it harder to have tests run in parallel on some systems.
For this specific situation, my solution is generally to provide a special class, say FileBuilder, that can instantiate new Files:
public class FileBuilder {
public java.io.File newFile(String pathname) {
return new java.io.File(pathname);
}
}
I then mock this class before passing it to MyClass, and instrument it as appropriate:
#Test(expected = Exception.class)
public void should_fail_when_file1_is_bigger_than_file2() {
FileBuilder mockFile1 = file(2L);
FileBuilder mockFile2 = file(1L);
FileBuilder mockFileBuilder = mock(FileBuilder.class);
when(mockFileBuilder.newFile("file1").thenReturn(mockFile1);
when(mockFileBuilder.newFile("file2").thenReturn(mockFile2);
new MyClass(mockFileBuilder).myMethodSpaceCheck();
}
private static File file(long length) {
File mockFile = mock(File.class);
when(mockFile.length()).thenReturn(length);
return mockFile;
}
(your example mentions File.size(); I assumed you meant File.length())
The actual implementation of MyClass would look like this:
public class MyClass {
private String file1;
private String file2;
private final FileBuilder fileBuilder;
public MyClass() {
this(new FileBuilder());
}
#VisibleForTesting
MyClass(FileBuilder fileBuilder) {
this.fileBuilder = fileBuilder;
}
public void myMethodSpaceCheck() //...
}