public class Foo {
public A getSomething() {
Properties file = loadProperties().getProperty(something);
}
public static Properties loadProperties() {
Properties properties = new Properties();
properties.load(Foo.class.getClassLoader().getResourceAsStream("id"));
}
return properties;
}
What I did is:
#InjectMocks
Foo foo = new Foo();
#Test
public void test() {
MockitoAnnotations.initMocks(this);
Properties properties = Mockito.mock(Properties.class);
Mockito.doNothing().when(properties).load(new FileInputStream("application.properties")
foo.getSomething();
}
It throws null pointer exception in properties.load method. Any help would be appreciated.
Thank you.
Related
I have class class1, which has 2 member variables:
classA
{
private Boolean isEnable;
private Config config;
public classA(final Config config)
{
this.config = config;
isEnable = config.getEnablingStatus();
}
public classB fun()
{
// Do something!
// Return an object of classB!
}
}
I want to test the method fun, so I will have to write a test-class and a test method for that. But, how do I mock the method call config.getEnablingStatus(), while creating an object of type classA in the test class?
I am thinking of doing something like this [see the below piece of code].Is it correct? But what is the right way to do it?
TestClassForClassA:
TestClassForClassA
{
private Boolean isEnable;
#Mock
private Config config;
#InjectMocks
classA objA = new classA(config);
#Before
public void init()
{
initMocks(this);
}
public void test1Fun()
{
// Does doing this, put the value of isEnable as true in the objA for this test?
isEnable = true;
// Here write the code to test the method fun().
}
public void test2Fun()
{
// Does doing this, put the value of isEnable as false in the objA for this test?
isEnable = false;
// Here write the code to test the method fun().
}
}
Do not use #InjectMocks
Try something like this
public class TestClassForClassA {
#Mock
private Config config;
private ClassA objA;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test1Fun() {
Mockito.when(config.getEnablingStatus()).thenReturn(true);
objA = new ClassA(config);
ClassB objB = objA.fun();
assertTrue(objB.isEnabled());
}
#Test
public void test2Fun() {
Mockito.when(config.getEnablingStatus()).thenReturn(false);
objA = new ClassA(config);
ClassB objB = objA.fun();
assertFalse(objB.isEnabled());
}
}
I have a scenario as follows that I'm not sure from where to start,
File name should be passed as an argument param when running the jar file
say for example I want to test a set of data from external file and I have a super class (Test Suite) that have number one and number two
and there are two test classes that should extend this class and perform the tests.
I'm currently new to JUnit so I'm lacking many concepts and need someone's help.
I have class CoreManager which executes the main
public static void main(String[] args)
{
if (Arrays.asList(args).contains("Import"))
{
accountInfo = new ArrayList<>();
int ImportIndex = Arrays.asList(args).indexOf("Import");
String fileName = args[ImportIndex+1];
if (fileName.contains("xml"))
{
ParseXML parseXML = new ParseXML();
accountInfo = parseXML.ParseAccounts(fileName);
Result result = JUnitCore.runClasses(LoginTestSuite.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
System.out.println(result.wasSuccessful());
}
}
}
And Suite Class
#RunWith(MockitoJUnitRunner.class)
#Suite.SuiteClasses({
Login.class,
SignUp.class
})
public class LoginTestSuite {
public static WebDriver driver;
public static ArrayList<AccountInfo> Account;
public static int SecondsToWait;
public LoginTestSuite(WebDriver driver,ArrayList<AccountInfo> Account,int
secondsToWait)
{
this.Account = Account;
this.SecondsToWait = secondsToWait;
this.driver = driver;
}
}
And Test Class
public class Login {
private static WebDriver driver;
private static ArrayList<AccountInfo> Account;
private static int SecondsToWait;
private static final Logger logger = Logger.getLogger(Login.class.getName());
#BeforeClass
public void init(){
this.driver = LoginTestSuite.driver;
this.Account = LoginTestSuite.Account;
this.SecondsToWait = LoginTestSuite.SecondsToWait;
}
#Before
public void Setup(){
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(SecondsToWait,
TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(SecondsToWait,
TimeUnit.SECONDS);
}
#After
public void TearDown(){
driver.quit();
}
#Test
public void TestUserLogin() throws Exception
{
// Logic
}
Your code looks muddled and contains several poor quality constructs. Most importantly, I don't see a distinction between test code and production code. Which is which?
This could be production code:
public class App {
public static void main(String[] args) {
AccountReader accountReader = new AccountReader();
List<AccountInfo> accounts = accountReader.read(args);
// maybe do something with those accounts?
}
}
public class AccountReader {
private ParseXML parseXML;
public AccountReader() {
this.parseXML = new ParseXML();
}
// extra constructor to allow dependency injection from test
protected AccountReader(ParseXML parseXML) {
this.parseXML = parseXML;
}
public List<AccountInfo> read(String[] args) {
return parseXML.ParseAccounts(getFileName(args));
}
private String getFileName(String[] args) {
List<String> arguments = Arrays.asList(args);
int importIndex = arguments.indexOf("Import");
if (importIndex < 0) {
throw new RuntimeException("Missing Import argument");
}
int fileNameIndex = importIndex + 1;
if (fileNameIndex >= arguments.size()) {
throw new RuntimeException("Missing fileName argument");
}
String fileName = args[fileNameIndex];
if (!fileName.endsWith(".xml")) {
throw new RuntimeException("Can only import XML files");
}
return fileName;
}
}
And this could be a test for it:
public AccountReaderTest {
private AccountReader instance;
#Mock // creates a mock instance which we can give desired behavior
private ParseXML parseXML;
#Mock
List<AccountInfo> accounts;
#Before
public void setUp() {
instance = new AccountReader(parseXML);
}
#Test
public void testHappy() {
// SETUP
String fileName = "test.xml";
// specify desired behavior of mock ParseXML instance
when(parseXML.ParseAccounts(fileName).thenReturn(accounts);
// CALL
List<AccountInfo> result = instance.read(new String[] { "Import", fileName });
// VERIFY
assertEquals(accounts, result);
}
#Test(expected = RuntimeException.class)
public void testMissingImport() {
instance.read(new String[] { "notImport" });
}
#Test(expected = RuntimeException.class)
public void testMissingFileName() {
instance.read(new String[] { "Import" });
}
#Test(expected = RuntimeException.class)
public void testNotXml() {
instance.read(new String[] { "Import", "test.properties"});
}
}
I have a class to be tested which is like this:
public class MainClass extends BaseClass {
public static int variableToBeAsserted= 0;
MainClass(ConfigClass config) {
super(config);
}
public void myMethod() {
List list = objectOfClass1inSuperClass.operation(objectOfClass2inSuperClass.method())
while(methodInSuperClass()) {
// doing operations with 'list'
variableToBeAsserted++;
}
}
// ..few other methods which I am not going to test.
}
I have suppressed the constructor of my BaseClass and my ConfigClass. Now my test class is like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class TestClass {
#Before
public void setUp(){
suppress(constructor(BaseClass.class))
suppress(constructor(ConfigClass.class))
}
#Test
public void testMyMethod(){
MainClass main = new MainClass(new ConfigClass(""));
List list1= new ArrayList();
test1.add("somevalues");
Class1inSuperClass ob1 = PowerMock.createMock(Class1inSuperClass.class);
Class2inSuperClass ob2 = PowerMock.createMock(Class2inSuperClass.class);
EasyMock.expect(ob2.method()).andReturn(getClass());
EasyMock.expect(ob1.operation(getClass())).andReturn(list1);
PowerMock.replayAll();
main.myMethod();
Assert.assertEquals(expectedValue, main.variableToBeAsserted);
}
}
Now I don't know why but my test case fails with a NullPointerException.
It tries to access objectofClass1inSuperClass and fails. I thought this will mock it. But it does not get mocked.
EDIT: I am writing only the test and I cannot change anything in BaseClass. However I have the option to modify the MainClass.
You have two ways to inject mock object to the object under the test.
Manually via WhiteBox
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class WhiteBoxApproachTestClass {
#Before
public void setUp() throws Exception {
suppress(constructor(BaseClass.class));
}
#Test
public void testMyMethod() {
MainClass main = new MainClass(createMock(ConfigClass.class));
List<String> list1 = new ArrayList<>();
list1.add("somevalues");
Class1inSuperClass ob1 = createMock(Class1inSuperClass.class);
Class2inSuperClass ob2 = createMock(Class2inSuperClass.class);
expect(ob2.method()).andReturn(getClass());
expect(ob1.operation(getClass())).andReturn(list1);
Whitebox.setInternalState(main, "objectOfClass1inSuperClass", ob1);
Whitebox.setInternalState(main, "objectOfClass2inSuperClass", ob2);
replayAll();
main.myMethod();
assertThat(MainClass.variableToBeAsserted).isEqualTo(5);
}
}
And via #TestSubject (http://easymock.org/user-guide.html#mocking-annotations)
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class TestSubjectApproachTestClass {
#Mock(fieldName = "objectOfClass1inSuperClass")
private Class1inSuperClass ob1;
#Mock(fieldName = "objectOfClass2inSuperClass")
private Class2inSuperClass ob2;
#TestSubject
private final MainClass main = new MainClass(createMock(ConfigClass.class));
#BeforeClass
public static void before() throws Exception {
suppress(constructor(BaseClass.class));
}
#Test
public void testMyMethod() {
List<String> list1= new ArrayList<>();
list1.add("somevalues");
expect(ob2.method()).andReturn(getClass());
expect(ob1.operation(getClass())).andReturn(list1);
EasyMockSupport.injectMocks(main);
replayAll();
main.myMethod();
assertThat(MainClass.variableToBeAsserted).isEqualTo(5);
}
}
Full code you may find here.
I'd like to change from which .properties file class should get them.
My class is like this now:
public class MyClass {
private String str;
public MyClass() throws IOException {
loadProperties();
}
private void loadProperties() throws IOException {
Properties props = new Properties();
props.load(getClass().getClassLoader().getResourceAsStream("my.properties"));
str= props.getProperty("property");
}
And whyle testing i would like properties to be loaded from another file.
It's apache camel app, so i have this now:
public class ConverterTest {
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new MyClass(); //--> Here i must load from another file
}
#Test
// test
}
Can this be achieved?
Just pass property file name to MyClass constructor
public MyClass(String propsFile) throws IOException {
loadProperties(propsFile);
}
There is something you can do:
public class MyClass {
private String str;
private String path = "my.properties";
public MyClass() throws IOException {
loadProperties();
}
protected void loadProperties() throws IOException {
Properties props = new Properties();
props.load(getClass().getClassLoader().getResourceAsStream(path));
str= props.getProperty("property");
}
And then, add a test to the same package with the code:
myClass = new MyClass();
ReflectionTestUtils.setField(path, "otherpathto.properties");
myClass.loadProperties();
It involves a small change in the code, but it might not be a big deal... depending on your project.
Arguably the cleanest solution would be to refactor MyClass and remove dependency on Properties object and inject the values needed via the constructor instead. Your case proves that hidden and hardcoded dependencies complicate testing.
Responsibility for reading the properties file and injecting the value into MyClass could be pushed back to its caller:
public class MyClass {
private final String str;
public MyClass(String strValue) {
this.str = strValue;
}
// ...
}
public class ProductionCode {
public someMethod() {
Properties props = new Properties();
props.load(getClass().getClassLoader().getResourceAsStream("my.properties"));
String str = props.getProperty("property");
MyClass obj = new MyClass(str);
obj.foo();
}
}
public class ConverterTest {
#Test
public void test() {
String testStr = "str for testing";
MyClass testee = new MyClass(testStr);
testee.foo();
// assertions
}
}
Need to create a class that i can load properties in and be able to call required properties from that class. such as propertiesClass.getname();
Here's my Class so far. I can't seem to initiate the property load.
So what i need is from another class in the project to just do (currently getting null)
String url = TestProperties.getBaseUrl();
*updated the class, here's what it looks like now.
public class TestProperties {
private static Properties testProperties;
private static String instanceUrl;
public TestProperties() throws Exception{
loadProperties();
getInstanceProperties();
instanceUrl = TestProperties.testProperties.getProperty("confluence.base.url","");
}
public static String getBaseUrl(){
return instanceUrl;
}
private void loadProperties() throws IOException {
InputStream testPropertiesInput = this.getClass().getClassLoader().getResourceAsStream("smoketest.properties");
TestProperties.testProperties = new Properties();
// if (null != testProperties) {
try{
TestProperties.testProperties.load(testPropertiesInput);
} finally {
IOUtils.closeQuietly(testPropertiesInput);
}
// }
}
}
my otherclass(){
String myurl = TestProperties.getBaseUrl();
}
The method
public void TestProperties() throws Exception{
was meant to be constructor but isn't one, so the class only gets a default no-arg constructor. Change that to:
public TestProperties() throws Exception{
i.e. remove the return type as constructors are distinguished from ordinary methods by not declaring a return type.
Please make sure you are able to rightly access your properties file smoketest.properties though InputStream testPropertiesInput.
EDIT:
There is no need to redefine the local variable in loadProperties and return it. It can be written very simply as:
private static void loadProperties() throws IOException {
InputStream testPropertiesInput = getClass().getClassLoader()
.getResourceAsStream("smoketest.properties");
Properties testProperties = new Properties();
try{
TestProperties.testProperties.load(testPropertiesInput);
} finally {
IOUtils.closeQuietly(testPropertiesInput);
}
TestProperties.testProperties = testProperties;
}
I think public void TestProperties() throws Exception{ is constructor of your class. If yes, please remove void from it as it making it as a method.
Finally you may want to use testProperties in your TestProperties() constructor as :
public TestProperties() throws Exception{
loadProperties();
getInstanceProperties();
instanceUrl = TestProperties.testProperties
.getProperty("confluence.base.url","");
}
Please Note: I don't think your class variables should be defined as static. Is there any reason of doing so?
EDIT: Here is the hopefully working sample code for you:
public class TestProperties {
private static Properties testProperties;
private static String instanceUrl;
public TestProperties(){
try{
loadProperties();
//getInstanceProperties();
instanceUrl = TestProperties.testProperties
.getProperty("confluence.base.url","");
}catch(IOException ioe){
ioe.printStackTrace();
}
}
static{
//Just to initialize the properties
new TestProperties();
}
private void loadProperties() throws IOException {
InputStream testPropertiesInput = getClass().getClassLoader()
.getResourceAsStream("smoketest.properties");
Properties testProperties = new Properties();
try{
testProperties.load(testPropertiesInput);
} finally {
IOUtils.closeQuietly(testPropertiesInput);
}
TestProperties.testProperties = testProperties;
}
public static String getBaseUrl(){
return instanceUrl;
}
public static String getPropertyValue(String key){
return TestProperties.testProperties.getProperty(key,"Not Found");
}
}
Now you can simply get your base URL any where as :
public static void main(String[] args) {
System.out.println(TestProperties.getBaseUrl());
System.out.println(TestProperties.getPropertyValue("confluence.base.url"));
System.out.println(TestProperties.getPropertyValue("test.property"));
}