I've implemented a feature in my jUnit tests that takes, for every test case, a fresh copy of a data source. This copy is taken in a folder specific for each test case. The idea is that every test case can start from a clean situation, manipulate it and let it as such after the run. This is often useful when the test fails for analysing the problem.
For now I have to call this feature directly in the test method because I don't know how to retrieve the current test name:
public void testTest1() {
TestHelper th=TestHelper.create("testTest1",subPathToDataSource);
// do the test...
Path dataPath = th.getDataPath();
...
}
I would like to be able to write something like this:
Path dataPath;
#Before
public initTest() {
th=TestHelper.create(SomeJUnitObject.getCurrentTestName(),subPathToDataSource);
...
}
public void testTest1() {
// do the test...
Path dataPath = th.getDataPath();
...
}
Until now I found as answers : "You don't need to know that"... But I do need it !
Is this possible ?
Kind regards
Look at the TestName rule.
You should be able to add in your test class:
#Rule TestName name=new TestName();
And then access it.
(On phone, so can't check versions support/details - might be 4.x only)
Here is an alternative approach; create an abstract class which your "real" test classes inherit.
I have several such examples in my projects and here I will give one, mainly testing for individual JSON Patch operations.
All my test files are JSON, and located under an appropriately named resource directory. The base, abstract class is JsonPatchOperationTest. And here is the full code of AddOperationTest which tests for JSON Patch's add operation:
public final class AddOperationTest
extends JsonPatchOperationTest
{
public AddOperationTest()
throws IOException
{
super("add");
}
}
And that's it! Not even one test method in this class, but of course your implementation may vary.
In your case you probably want to pass the directory name as a constructor argument, or the like.
Related
I have a class named SpecialClass. This class has the method doSomething in it. This class is in this particular manner special, that I do not want to mock this class at all via MockedStatic. It is very easy for me to remeber that I don't want to mock this class, but there are other people programming at the same project and they should know to not mock this class but I can not relate on it.
Given this special test:
#Test
void testSomething(){
try(MockedStatic<SpecialClass> mock = Mockito.mockStatic(SpecialClass.class)){
mock.when(SpecialClass::doSomething).thenReturn(0);
System.out.println(SpecialClass.doSomething());
}
}
I dont want to let this test execute at all. But it will execute, because Mockito does not know about my SpecialClass and not to mock it. There could be also various other locations where SpecialClass could be mocked.
Some classes can not be mocked because of Mockito decides so. Given this mock of java.lang.System:
#Test
void testFail(){
try(MockedStatic<System> sys = Mockito.mockStatic(System.class)){
// some code
}
}
I get the exception org.mockito.exceptions.base.MockitoException: It is not possible to mock static methods of java.lang.System to avoid interfering with class loading what leads to infinite loops, which is ok.
My question is: Can I somehow have some global project settings (or some annoations) to mark my class SpecialClass to be not used in Mockitos MockedStatic? I would be also ok if I can also not mock this class in a normal way.
I tried to find some information regarding restricting mocks, but i was unable to find some.
My mockito version of mockito-core and mockito-inline is 4.3.1
I used a junit test to read all my files and trying to detect all mocks.
Please note that my test is working in a very special assumption that all of my test classes are in the same directory. This will hoever not be given in every project. In this case you will need to find the files recursivly.
class NoStaticMockTest {
#Test
void testNoMocks() throws IOException {
// Base dir of my tests
File testDir = new File("src/test/java");
// reading all Files in the test directory excluding this file
for (File file : testDir.listFiles(pathname -> !pathname.getAbsolutePath().endsWith("NoStaticMockTest.java") && pathname.isFile())) {
try (FileInputStream fis = new FileInputStream(file)) {
// Reading the contennt and trying to find MockedStatic<SpecialClass>
String content = IOUtils.toString(fis);
if (content.contains("MockedStatic<SpecialClass>")) {
Assertions.fail(file.getAbsolutePath() + " used MockedStatic<SpecialClass> which is not allowed");
}
}
}
}
}
I want to pass a dynamic parameter to a test case from testng xml, my parameter is something like:
String dynamicParameter=generateRandomStringForMail();
Here is my testcase:
#Test()
public void customerCreatorAllProducts () throws Exception {
setup();
Functions.pages.LoginPage login = PageFactory.initElements(driver, Functions.pages.LoginPage.class);
login.navigateRegisterPage().createFixedPasswordCustomerRequiredFields(dynamicParameter);
}
I will be using this parameter in other cases as well, how can i do this from testng.xml or with something else?
I am not familiar with testing.xml, but Mockito immediately comes to mind for this: http://mockito.org.
add Mockito to your project (e.g. through the build.gradle page)
add the import to your test file:
import static org.mockito.Mockito.*;
within your test class, create a mock of the class which has the generateRandomStringForMail() method. In my current project, I have
DefaultFileService mockFileService = mock(DefaultFileService.class);
define what you want the method to return under these test conditions, e.g.
when(mockFileService.generateRandomFileName()).thenReturn("fileName");
Whenever your tests need to use the result of the method in question, you can use "fileName", because you have told the test environment to give this response. My project has a method to update the image file associated with an inventory item, which process includes using the DefaultFileService to generate a random file name, then passing the image file and the new file name to the DefaultFileService to save the file in the system. My test code can't see or guess what file name would actually be produced, but my 'when' line above has resolved that problem for the purposes of testing my QuiltController class:
quiltController.update(data, mockFile);
verify(mockFileService).save(mockFile, "fileName"); // confirms the save() method was called with the expected parameters
It feels pretty similar to what you are trying to do, so hopefully that helps you proceed if you do want to explore Mockito. Don't be surprised if you need to refactor some of your work to make it more testable. I did, and have better code as a result. Give it a go :)
I am trying to test utility method which check if particular class is on class path, if yes return true else return false.
Why I am doing this: I have to independent classes extending same class, and only one of it will be on classpath. Need to do specific thing if one particular is on classpath.
Using kind of below method to check if particular class is on class path.
This check will be done only once after first request.
I'd checked Class.forName() also but decided to go with below approach.
My utility method looks something like this:
public static boolean isMyClassOnClassPath() {
try {
ClassLoader.getSystemClassLoader().loadClass("com.MyClass");
return true;
} catch (ClassNotFoundException ex) {
return false;
}
}
Checking false condition is easy as particular class is not not the ClassPath.
I'm trying to write Junit for positive scenario when this method will return true.
#Test
public void isMyClassOnClassPathShouldReturnTrueWhenMyClassIsOnClassPath() throws Exception{
PowerMockito.mockStatic(MyClass.class);
ClassLoader classLoader = PowerMockito.mock(ClassLoader.class);
PowerMockito.mockStatic(ClassLoader.class);
PowerMockito.when(ClassLoader.getSystemClassLoader()).thenReturn(classLoader);
//trying to mock classLoader.loadClass, below way is incorrect
//PowerMockito.when(classLoader.loadClass("com.MyClass")).thenReturn(Class<java.lang.Object.class>);
Assert.assertTrue(MyClassUtil.isMyClassOnClassPath());
}
So is it possible to mock classLoader.loadClass() method?
Honestly: don't even think about doing something like that.
In short, you are like a person sitting on a tree that starts cutting random limbs of the tree that person is sitting on. Meaning: this is a central part of the JVM. Assume your mocking would work: then every caller to that method would receive your mocked loader! So, when your test case itself wanted to load some classes, it would run into your mock!
And as almost usual, when people claim "I need to user Powermock for xyz" your real problem is a different one: you created untestable code. By making that static call there, you prevent yourself from testing your code!
For starters, you can have a look here to learn how to write testable code. But in case you are curious how you could fix your design:
class ClassPathChecker {
private final ClassLoader classLoader;
ClassPathChecker() { this(ClassLoader.getSystemClassLoader()); }
ClassPathChecker(ClassLoader classLoader) {
this.classLoader = this.classLoader);
}
boolean canClassBeLoaded(String className) {
try {
classLoader.loadClass ...
The above uses dependency injection to insert a mocked ClassLoader; which gives you full control over everything that is going on. Without using Powermock at all.
And out of curiosity: why do you restrict yourself to the System classloader? Wouldn't a simple call like Class.forName("yourclass") tell you the same?
I have a folder path set in system variable through JVM arguments in Eclipse and I am trying to access it in my class as:
System.getProperty("my_files_path").
While writing junit test method for this class, I tried mocking this call as test classes do not consider JVM arguments. I have used PowerMockito to mock static System class and tried returning some path when System.getProperpty is being called.
Had #RunWith(PowerMockRunner.class) and #PrepareForTest(System.class) annotations at class level. However, System class is not getting mocked as a result I always get null result.
Any help is appreciated.
Thanks Satish. This works except with a small modification. I wrote PrepareForTest(PathFinder.class), preparing the class I am testing for test cases instead of System.class
Also, as mock works only once, I called my method right after mocking.
My code just for reference:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PathInformation.class)
public class PathInformationTest {
private PathFinder pathFinder = new PathFinder();
#Test
public void testValidHTMLFilePath() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("my_files_path")).thenReturn("abc");
assertEquals("abc",pathFinder.getHtmlFolderPath());
}
}
There are certain classes PowerMock can't mock in the usual way. See here:
https://code.google.com/p/powermock/wiki/MockSystem
This, however, may still not work. In order of "good design" preference, you can fall back to these:
Refactor your code! Using a System property for passing a file path around is probably not the best way. Why not use a properties file loaded into a Properties object? Why not use getters/setters for the components that need to know this path? There are many better ways to do this.
The only reason I could think of not to do this is you're trying to wrap a test harness around code you "can't" modify.
Use #Before and #After methods to set the System property to some known value for the test(s). You could even make it part of the #Test method itself. This will be FAR easier than attempting to mock through PowerMock. Just call System.setProperty("my_files_path","fake_path");
System class is declared as final and cannot be mocked by libraries such as PowerMock. Several answers posted here are incorrect. If you are using Apache System Utils you can use getEnvironmentVariable method instead of calling System.getenv directly. SystemUtils can be mocked since it is not declared as final.
Set the system property in your test and ensure that it is restored after the test by using the rule RestoreSystemProperties of the library System Rules.
public class PathInformationTest {
private PathFinder pathFinder = new PathFinder();
#Rule
public TestRule restoreSystemProperties = new RestoreSystemProperties();
#Test
public void testValidHTMLFilePath() {
System.setProperty("my_files_path", "abc");
assertEquals("abc",pathFinder.getHtmlFolderPath());
}
}
The System.setter or getter method should be put in a user defined method and that method can be mocked to return the desired property in unit test.
public String getSysEnv(){
return System.getEnv("thisprp");
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(System.class)
public class MySuperClassTest {
#Test
public void test(){
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("java.home")).thenReturn("abc");
System.out.println(System.getProperty("java.home"));
}
}
Sailaja add System.class because as per the power mock guidelines for static,private mocking you should add the class in prepare for test.
#PrepareForTest({PathInformation.class,System.class})
Hope this helps.let me know if it doesn't work
I have a very strange problem, when i try to run a JUnit test with multiple test case, it will only pass the first test case and shown IndexOut of Bound error
public class ABCTest {
#Test
public void basicTest1(){...}
#Test
public void basicTest2(){...}
...
but if i commend the rest test case, test them one by one, it will pass all of them.
public class ABCTest {
#Test
public void basicTest1(){...}
//#Test
//public void basicTest2(){...}
//...
Since you do not provide the complete testcase and implementation class, I have to make some assumptions.
Most likely you are mutating the state of the tested object by the testcase.
Usually you try to get a clean test fixture for each unit test. This works by having a method with the #Before annotation which creates a new instance of the class under test. (This was called 'setUp()' in older versions of junit.)
This ensures that the order of test method execution as well as the number of executions does not matter and each method is working isolated.
Look at what you are doing inside of the test case and see if you are changing data that may be used by the other test cases and not restoring it to the original state. For example you have a text file that you read and write to in basicTest1 that you then read again in basicTest2 but assume the file is the same as it was before you ran basicTest1.
This is just one possible problem. would need to see the code for more insight