How to run test cases with given custom annotation - java

I want to run integration tests only if it has given annotation. The thing is that test cases need some variables which are needed to be initialized in #Before and destroyed in #After.
I wrote the code which executes the tests which have given annotation, but they all fail because of the variables which need to be initialized in #Before phase.
I first invoke #Before phase(I suppose the variables are initialized), then run the test method, then invoke #After phase. But I get NullPointerException in test method.
How to initialize variable for the test methods?? Isn't enough to invoke #Before phase??
The code I have:
public static void main(String[] args) throws Exception {
Class<TodoMapperTest> obj = TodoMapperTest.class;
int passed = 0;
int failed = 0;
int count = 0;
for (Method method : obj.getDeclaredMethods()) {
if (method.isAnnotationPresent(Before.class))
method.invoke(obj.newInstance());
if (method.isAnnotationPresent(DEV.class)) {
try {
method.invoke(obj.newInstance());
System.out.printf("%s - Test '%s' - passed %n", ++count, method.getName());
passed++;
} catch (Throwable ex) {
System.out.printf("%s - Test '%s' - failed: %s %n", ++count, method.getName(), ex);
failed++;
}
}
if (method.isAnnotationPresent(After.class))
method.invoke(obj.newInstance());
}
System.out.printf("%nResult : Total : %d, Passed: %d, Failed %d%n", count, passed, failed);
}
#Before phase:
TodoQueryMapper mapper;
SqlSession session;
#Before
public void setUp() throws Exception {
InputStream inputStream = Resources.getResourceAsStream("todo-mybatis/mybatis-test.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
inputStream.close();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(TodoQueryMapper.class);
}
Edit:
Test case:
#Test
#DEV
public void test_case() throws Exception {
SqlParams params = new SqlParams();
params.idList = Collections.singletonList(1234567);
// In here, 'mapper' variable is null, even #Before invoked
List<TodoDto> data = mapper.findByIdList(params);
assertEquals(1, data.size());
}
DEV Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface DEV {
}

Each time you invoke a method via reflection you create a new instance of your test class: method.invoke(obj.newInstance());
You should seperate your test execution in three phases: Before, Test and After. Iterate over the Test-methods, find the Before- and After-method and execute them in the desired order.
Pseudo code:
Class<AccountDaoMapperTest> objClass = AccountDaoMapperTest.class;
for (Method testMethod : findTestMethods(objClass)) {
AccountDaoMapperTest objUnderTest = objClass.newInstance();
findBeforeMethod(objClass).invoke(objUnderTest);
testMethod.invoke(objUnderTest);
findAfterMethod(objClass).invoke(objUnderTest);
}

Related

Getting "Wanted but not invoked" when running unit test

Trying to test repository method, but my test fails with following "Wanted but not invoked: cellphonesDao.deleteAllCellphones();"
Here is repo method:
#Override
public Single<Cellphone[]> getCellphones() {
Single<CellPhoneEntity[]> remoteCellphones =
networkModule.productApi()
.getCellPhones()
.onErrorResumeNext(cellphonesDao.getAllCellphones()); // todo return value if true
Single<CellPhoneEntity[]> localCellphones = cellphonesDao.getAllCellphones();
return Single.zip(remoteCellphones, localCellphones, (remote, local) -> {
if (!Arrays.equals(remote, local)) {
cellphonesDao.deleteAllCellphones();
for (CellPhoneEntity cellPhoneEntity : remote) {
cellphonesDao.insertCellphone(cellPhoneEntity);
}
}
return mapper.toCellphones(remote);
});
}
Main porpuse is to test repo method in correct way. Guess the way I chose is not good.
Here is test implementation:
class CellPhoneRepositoryImplTest {
NetworkModule networkModule;
CellphonesDao cellphonesDao;
CellphoneMapper cellphoneMapper;
CellPhoneRepositoryImpl cellPhoneRepository;
ProductAPI productAPI;
#BeforeEach
void setUp() {
networkModule = Mockito.mock(NetworkModule.class);
cellphonesDao = Mockito.mock(CellphonesDao.class);
productAPI = Mockito.mock(ProductAPI.class);
cellphoneMapper = new CellphoneMapper();
cellPhoneRepository = Mockito.spy(new CellPhoneRepositoryImpl(
networkModule,
cellphonesDao,
cellphoneMapper
));
}
#Test
void whenRemoteDataAreDifferentFromLocalDbIsUpdated() {
int numberOfCellphones = 5;
CellPhoneEntity[] remoteCellphones = DummyCellphoneEntityFactory.generateCellphones(numberOfCellphones);
CellPhoneEntity[] localCellphones = DummyCellphoneEntityFactory.generateCellphones(numberOfCellphones);
Mockito.when(networkModule.productApi()).thenReturn(productAPI);
Mockito.when(networkModule.productApi().getCellPhones()).thenReturn(wrapWithSingle(remoteCellphones));
// Mockito.when(networkModule.productApi().getCellPhones().onErrorResumeNext(cellphonesDao.getAllCellphones())).thenReturn(wrapWithSingle(remoteCellphones));
Mockito.when(cellphonesDao.getAllCellphones()).thenReturn(wrapWithSingle(localCellphones));
Mockito.doNothing().when(cellphonesDao).deleteAllCellphones();
cellPhoneRepository.getCellphones();
Mockito.verify(cellphonesDao, Mockito.times(1))
.deleteAllCellphones();
}
private Single<CellPhoneEntity[]> wrapWithSingle(CellPhoneEntity[] cellphones) {
return Single.just(cellphones);
}
}
I will be glad for any suggestion)
The code inside the returned Single isn't executed immediately, but your verifications are. Try calling cellPhoneRepository.getCellphones().blockingGet() instead of just cellPhoneRepository.getCellphones(). The blockingGet() should make your test wait until the Single is done executing.

Testing method having CompletableFuture.allOf using mockito

I have a method called doParallelThings:
public Dummy doParallelThings(Map<String, String> mapp) throws Exception {
Dummy dummy = new Dummy();
CompletableFuture<Ans1> one = firstService.getOne(mapp.get("some1"), mapp);
CompletableFuture<Ans2> two = secondService.getTwo(headersMap.get("some2"), mapp);
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(one, two);
try {
combinedFuture.get();
dummy.setOne(one.get());
dummy.setTwp(two.get());
} catch (Throwable e) {
}
return dummy;
}
Code works fine but when I'm trying to test it,
combinedFuture.get(); goes to infinite loop.
Unit test is as below:
#Mock
private CompletableFuture<Void> ans;
#Test
public void testDoParallelThings() throws Exception {
PowerMockito.mockStatic(CompletableFuture.class);
PowerMockito.when(CompletableFuture.allOf(any())).thenReturn(ans);
when(ans.get()).thenReturn(null);
Dummy dummy = dummyService. doParallelThings(mockMap);
assertNotNull(dummy);
}
I have also added #RunWith(PowerMockRunner.class)
#PrepareForTest({CompletableFuture.class}) above the test class.
What am I missing?
when(firstService.getOne(any(), any())).thenReturn(CompletableFuture.completedFuture(mockOne));
solved my problem

How to assert "N" exceptions have been thrown in this unit test?

I've got the following unit test, which works almost fine:
#Test(expectedExceptions = {IllegalArgumentException.class}, expectedExceptionsMessageRegExp =
PasswordValidator.INVALID_PASSWORD)
public void testInvalidPasswordsThrowException() throws Exception {
for (String invalidPassword: getInvalidPasswords()){
new LaxPasswordValidator(invalidPassword);
}
}
private String[] getInvalidPasswords() {
return new String[] {INVALID_PASSWORD_1, INVALID_PASSWORD_2, INVALID_PASSWORD_3, INVALID_PASSWORD_4,
INVALID_PASSWORD_5, INVALID_PASSWORD_6, INVALID_PASSWORD_7, INVALID_PASSWORD_8, INVALID_PASSWORD_9,
INVALID_PASSWORD_10};
}
As you can see, it is just asserting that new LaxPasswordValidator(invalidPassword) works as expected and throws an exception.
Problem: It is just taking INVALID_PASSWORD_1 into account, so it stops in the first iteration; it launches the exception but does not continue checking the other passwords. How can I make it test them all? Thanks
You must annotate the method as #DataProvider
#DataProvider(name = "invalid-passwords")
public Object[][] getInvalidPasswords() {
return new String[][]{
{"INVALID_PASSWORD_1"},
{"INVALID_PASSWORD_2"},
{"INVALID_PASSWORD_3"}
};
}
and annotate the #Test method to use this dataprovider for the parameters.
#Test(expectedExceptions = {IllegalArgumentException.class},
expectedExceptionsMessageRegExp = PasswordValidator.INVALID_PASSWORD,
dataProvider = "invalid-passwords")
public void testInvalidPasswords(String password) throws Exception {
new LaxPasswordValidator(password);
}

Get a reference of an object using class name Java

I'm Running a method annotated with #Test and I want get a reference to the object JunitCore, this object invokes the method by reflection.
How can I get a reference to the that object, If It's possible?(maybe a security issue)
I tried reflection and classLoader but I couldn't make it work.
Thanks
The JUnitCore is a basic entry point for Junit tests. The way it works is it finds a List of classes provided as java command arguments and uses them to create a Runner with which it runs the test cases.
At no point during processing does the main method in JUnitCore ever pass a reference of the JUnitCore instance it creates to any other object. As such, it is not retrievable either directly or with reflection.
JUnitCore is as follows
public static void main(String... args) {
runMainAndExit(new RealSystem(), args);
}
public static void runMainAndExit(JUnitSystem system, String... args) {
Result result= new JUnitCore().runMain(system, args);
system.exit(result.wasSuccessful() ? 0 : 1);
}
public Result runMain(JUnitSystem system, String... args) {
system.out().println("JUnit version " + Version.id());
List<Class<?>> classes= new ArrayList<Class<?>>();
List<Failure> missingClasses= new ArrayList<Failure>();
for (String each : args)
try {
classes.add(Class.forName(each));
} catch (ClassNotFoundException e) {
system.out().println("Could not find class: " + each);
Description description= Description.createSuiteDescription(each);
Failure failure= new Failure(description, e);
missingClasses.add(failure);
}
RunListener listener= new TextListener(system);
addListener(listener);
Result result= run(classes.toArray(new Class[0]));
for (Failure each : missingClasses)
result.getFailures().add(each);
return result;
}
... // and more
No where in this implementation is a reference to this passed as an argument. As such, you cannot get a reference to it.
The only way is to create a JunitCore instance and run the tests yourself:
JUnitCore junit = new JUnitCore();
//we can add a listener to listen for events as we run the tests
junit.addListener(new RunListener(){
#Override
public void testFailure(Failure failure) throws Exception {
System.out.println("failed " + failure);
}
});
Result result = junit.run(Class.forName(nameOfTestSuite));

PowerMock's expectNew() isn't mocking a constructor as expected

I'm trying to learn the ins and outs of various mocking libraries and PowerMock(specifically the EasyMock extension) is next on the list. I'm attempting to mock a constructor and the examples provided don't have the same response when I try to replicate them. As far as I can tell, it never mocks the constructor and just proceeds as if it were normal.
This is the test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Writer.class})
public class FaultInjectionSituationTest {
#Test
public void testActionFail() throws Exception {
FaultInjectionSituation fis = new FaultInjectionSituation();
PowerMock.expectNew(Writer.class, "test")
.andThrow(new IOException("thrown from mock"));
PowerMock.replay(Writer.class);
System.out.println(fis.action());
PowerMock.verify(Writer.class);
}
}
I've tried replacing the "test" with an EasyMock.isA(String.class), but it yielded the same results.
This is the FaultInjectionSituation:
public class FaultInjectionSituation {
public String action(){
Writer w;
try {
w = new Writer("test");
} catch (IOException e) {
System.out.println("thrown: " + e.getMessage());
return e.getLocalizedMessage();
}
return "returned without throw";
}
}
The "Writer" is nothing more than a shell of a class:
public class Writer {
public Writer(String s) throws IOException {
}
public Writer() throws IOException{
}
}
When the test is run, it prints out "returned without throw", indicating the exception was never thrown.
You need to prepare the class that is calling the constructor as well, so PowerMock knows to expect a mocked constructor call. Try updating your code with the following:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Writer.class, FaultInjectionSituation.class})
public class FaultInjectionSituationTest {
// as before
}
You need to first create a mock object:
Writer mockWriter = PowerMock.createMock(Writer.class)
PowerMock.expectNew(Writer.class, "test").andReturn(mockWriter)

Categories

Resources