I'm going to develop a Class for accessing mysql db. It looks something like this -
class DB {
public void update(String,String) {....}
public void delete(String,String) {....}
.
.
.
}
Now...I would like to unit test each method of this class. Instead of writing unit tests for each method..is there any way to create unit tests programmatically ?
I tried doing this -
DB db = new DB();
Method method = db.getClass().getMethod("method name",String.class,String.class);
method.invoke(db,"params");
this is working, but how do I create a junit test for each method in the DB class ?
Related
Given the following service method in a Spring Boot application:
#Transactional
public void updateCategory(long categoryId, CategoryData categoryData) {
final Category category = categoryRepository.findById(categoryId).orElseThrow(EntityNotFoundException::new);
category.setName(categoryData.getName());
}
I know how to instruct Mockito to mock the categoryRepository.findById() result.
However, I couldn't figure out yet: Is it possible to verify that category.setName() was called with the exact argument of categoryData.getName()?
You are looking for Mockito.verify, and a test looking like:
#ExtendWith(MockitoExtension.class)
public class CategoryServiceTest {
#Mock
CategoryRepository categoryRepository;
#InjectMocks
CategoryService categoryService;
#Test
public void testUpdateCategoryMarksEntityDirty() {
// given
long categoryId = 1L;
Category category = mock(Category.class);
String newCategoryName = "NewCategoryName";
when(categoryRepository.findById(categoryId)).thenReturn(Optional.of(category));
// when
categoryService.updateCategory(categoryId, new CategoryData(newCategoryName));
// then
verify(category, times(1)).setName(newCategoryName);
}
}
I must, however, advise against this style of testing.
Your code suggests that you are using a DB Access library with dirty-checking mechanism (JPA / Hibernate?). Your test focuses on the details of interaction with your DB Access layer, instead of business requirement - the update is successfully saved in the DB.
Thus, I would opt for a test against a real db, with following steps:
given: insert a Category into your DB
when: CategoryService.update is called
then: subsequent calls to categoryRepository.findById return updated entity.
I have implemented a generic TestBase.java and many test case class extends this base.
#BeforeClass method is to prepare some specific data for corresponding test case class.
My question is, is it possible to get the invoking test case classname in TestBase #BeforeClass method so that I can use the classname to get correct data prepared?
I don't want to implement the #BeforeClass in separate test case class, as the steps are totally the same, the only difference is the data name which can be generated by test case classname.
For example:
My project is to test query function of our product.
Test case classes like GenericQueryTest.java, BooleanQueryTest.java etc.
Each test case class need to index prepared data before run test and cleanup the environment after all tests in the testcase class finish.
I implemented a TestBase.java like following.
public class TestBase {
#BeforeClass
public static void setUpBeforeClass() throws Exception {
I want to get invoked test case class name here. if I get the name(eg. classname= "GenericQueryTest ")
File testDataFile = new File("C:/users/" + classname +".csv";
then read the "C:/users/GenericQueryTest.csv "to prepare data in env
}
public class GenericQueryTest extends TestBase{
I donot need to implement #BeforeClass
#Test
.....
#Test
...
}
I figured out how to resolve the problem. Just implement customized runner. And you can get Class from the runner.
#RunWith(DataProviderRunner.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class DatabaseModelTest {
// some tests
}
or
#RunWith(Parameterized.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class DatabaseModelTest {
// some tests
}
We can not use two runner property in one test case class...!! so that
I want to run test case with Multiple data how i pass multiple parameter in Rest web service to execute test case ??
Any solution for extend class for DataProviderRunner or parameterized ??
Thanks
(stayconnected52)
You could use Spring's JUnit rules instead of the SpringJUnit4ClassRunner. This works at least with the Parameterized runner. I don't know whether it works with the DataProviderRunner, too.
You need at least version 4.2.0 of the Spring framework and spring-test.
#RunWith(Parameterized.class)
public class DatabaseModelTest {
#ClassRule
public static final SpringClassRule SCR = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
...
}
I tested the solution of #Stefan and works also well for #RunWith(DataProviderRunner.class)
I found a second solution in DataProvider for Spring Integration Testing, they wrote a class DataProviderRunnerWithSpring and set the test class like:
#RunWith(DataProviderRunnerWithSpring.class)
public class TestClass{
...
}
I'm currently creation JUnit test for a play application. The problem comes when I try to use FakeApplication. I create one in JUnit test but when a test uses the fakeApplication instance, then I got this:
[error] Test controllers.MyClassTest.getMyProperty failed: play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [default]]
Here's my Java code in the JUnit test class:
...
#BeforeClass
public static void startFakeApplication() {
Map<String, String> settings = new HashMap<String, String>();
settings.put("db.default.url", "jdbc:mysql://myhost/releaseDB?characterEncoding=UTF-8");
settings.put("db.default.driver", "com.mysql.jdbc.Driver");
settings.put("db.default.user", "release");
settings.put("db.default.password", "release");
settings.put("db.default.jndiName", "DefaultDS");
Helpers.start(fakeApplication);
}
...
Then my method to test (notice the dummy run so nothing should cause any trouble):
...
public void getMyProperty() {
Helpers.running (fakeApplication, new Runnable() {
public void run() {
}
});
}
...
I think the problem is a database connection issue, and of course when running play in run mode, everything is fine. If I don't use FakeApplication then it's fine also but I need it.
All the database information in startFakeApplication method are coming from conf/application.conf so they're right.
What is strange is that I also have this line in the output screen when running test:
[info] play - datasource [jdbc:mysql://myhost/releaseDB?characterEncoding=UTF-8] bound to JNDI as DefaultDS
Did I missed something important here ?
Thx
Are you passing your settings map to fakeApplication somewhere? Something like:
FakeApplication fakeApplication = fakeApplication(settings);
An alternative option is to have a separate application-test.conf file and include the following in your build.sbt file:
javaOptions in Test ++= Seq(
"-Dconfig.file=conf/application-test.conf"
)
My framework Acolyte provides a JDBC driver & tools, designed for such purposes (mock up, testing, ...): http://acolyte.eu.org
It's used already in some open source projects (Anorm, Youtube Vitess, ...), either in vanilla Java, or using its Scala DSL.
val jdbcUrl = "jdbc:acolyte:anything-you-want?handler=my-unique-id"
val handler = handleStatement.withQueryDetection(...).
withQueryHandler(/* which result for which query */).
withUpdateHandler(/* which result for which update */).
// Register prepared handler with expected ID 'my-unique-id'
acolyte.Driver.register("my-unique-id", handler);
// then ...
Connection con = DriverManager.getConnection(jdbcUrl);
// ... Connection |con| is managed through |handler|
// Or pass the JDBC url to Play config
I wanted to know if there's any way to add test suites dynamically in junit 4.
For example I have a TestClassA as mentioned below having test case "test1"
class TestClassA
{
#Test
public void test1()
{
createTestClassDynamically(); // this creates a test class having
// setUp(), tearDown() methods and one test case .
}
}
Test case test1 has a method createTestClassDynamically() that dynamically creates a new test class (lets say TestClassB) having setUp(), tearDown() methods and one test case (lets say test2()).
I want to run the test1 and then when TestClassB is dynamically generated I want test case "test2" also to be executed.
I know this is quite complicated and not the best thing to do but in my framework I need to do it to generate large number of test classes dynamically rather than having them physically in the package.
Can anyone please provide any help/suggestions?
I have solved this is my framework using the Parameterized feature of Junit 4 which helps to execute same test case with different parameters.
Below mentioned is the sample code on how I acheived it, thought to post it if it helps anyone.
Also, if someone has a better solution, feel free to post it.
class TestClassA
{
private TestClassB classBObj;
public TestClassA(TestClassB obj) {
classBObj= obj;
}
#Test
public void test1()
{
// createTestClassDynamically(); // remove this method as Parameterized
// feature will take care of dynamic test execution.
}
#Test
public void test2()
{
// Test case from Test class B using TestClassB object (classBObj)
}
public static Collection<Object[]> getParameters() {
Collection<Object[]> parameteres = new ArrayList<Object[]>();
Object[] obj1 = new Object[]{new TestClassB()};
Object[] obj2 = new Object[]{new TestClassB()};
parameteres.add(obj1);
parameteres.add(obj2);
// ....... add more test data this way or create a loop
return parameteres;
}
}