I am writing unit tests for fetching records from Oracle DB using JOOQ library and I need to mock data returned by DSLContext's fetch() function. How can I create sample Result<Record> to be returned by mocked function? I googled it for few hours and could not find an answer.
Try to use JOOQ's own mock API. Here are the official docs
You probably want to end up with something like that:
final MockDataProvider myMockProvider = new MockDataProvider() {
#Override
public MockResult[] execute(final MockExecuteContext context) throws SQLException {
final DSLContext context = DSL.using(SQLDialect.ORACLE);
final Result<Record> resultRecord = context.newResult(YOUR_TABLE_HERE);
// customize your record with needed fields
resultRecord.add(context.newRecord(YOUR_TABLE_HERE));
return new MockResult[] { new MockResult(1, resultRecord) };
}
};
final DSLContext mockedDSL = DSL.using(new MockConnection(myMockProvider), SQLDialect.ORACLE);
// here you go with your tests
I've faced the same issue, and I didn't want to have a MockDataProvider, as I was testing something else than the DAO. Therefore, I created a trivial function in order to convert a Record (or multiple) into a Result<T>.
Note that this is in Kotlin, but it should be easy to translate this into Java:
val jooq = DSL.using(SQLDialect.POSTGRES)
fun <T : Record> result(table: TableImpl<T>, vararg data: T): Result<T> {
return jooq.newResult(table).apply { addAll(data) }
}
Which then can be used as follows:
result(TABLE_NAME, <a record>, <another record>)
And records can just be created using their constructors.
Related
I'm using camel version 3.14.5 and I'm wondering if there's a way (I can't see one) where I can use a customBeanPropertyRowMapper when using a SqlEndpoint.
I'm using the sql endpoint like this in a route:
.to("mySqlComponent:classpath:my_sql.sql?outputType=StreamList&outputClass=com.my.project.MyCustomMappedPojo")
Looking at the code it does look like a BeanPropertyRowMapper is hardcoded in the class
DefaultSqlEndpoint
#SuppressWarnings("unchecked")
public ResultSetIterator queryForStreamList(Connection connection, Statement statement, ResultSet rs) throws SQLException {
if (outputClass == null) {
RowMapper rowMapper = new ColumnMapRowMapper();
return new ResultSetIterator(connection, statement, rs, rowMapper);
} else {
Class<?> outputClzz = getCamelContext().getClassResolver().resolveClass(outputClass);
RowMapper rowMapper = new BeanPropertyRowMapper(outputClzz);
return new ResultSetIterator(connection, statement, rs, rowMapper);
}
}
So all I'm after is a way to make use of a Custom RowMapper.
The most obvious way would be to pass it to the SqlEndpoint directly, but there's no such property.
Alternatively I thought about using a custom SqlEndpoint whilst wiring a SqlComponent in Spring, but I see that the SqlComponent uses a SqlEndpoint hardcoded (i.e.: doesn't allow me to inject a custom Endpoint) which in turns uses the hardcoded BeanPropertyRowMapper as per the code sample above.
I am using Quarkus with Hibernate-ORM PanacheRepository and I need to mock the PanacheQuery.
I have the following classes:
Label(JPA Entity)
LabelRepository (implements PanacheRepository< Label > {})
In my test class I need to mock the labelRepository.find("name", name). This method return a PanacheQuery but I don't know how I can create a new PanacheQuery mock.
#QuarkusTest
class LabelResourceTest {
#Inject LabelResource labelResource;
#InjectMock LabelRepository labelRepository;
private Label label;
private List<Label> labels;
#BeforeEach
void setUp() {
label = new Label();
label.setId(1L);
label.setName("LABEL#01");
label.setInheritable(true);
labels = new ArrayList<>();
labels.add(label);
}
#Test
void getNameTest() {
when(labelRepository.find("name", "LABEL#01")).thenReturn(......);
.....
}
}
Thank you.
The final working piece of code (thanks to #loicmathieu):
PanacheQuery query = Mockito.mock(PanacheQuery.class);
Mockito.when(query.page(Mockito.any())).thenReturn(query);
Mockito.when(query.firstResultOptional()).thenReturn(Optional.of(label));
when(labelRepository.find("name", "LABEL#01")).thenReturn(query);
I my case I have used the firstResultOptional() method but you can replace it if you need to use the list() because you are getting the entire list and not only a single item.
This is a very good point !
Today, there is no easy way to mock a PanacheQuery. Depending on the Panache flavor, a PanacheQuery is backed with a JPA Query (for Hibernate) or a BSON Query (for MongoDB) and have the capability to act on this query object (for example, paginate).
As of today, you may need to create a Mock on the PanacheQuery interface and return this mock on your when(labelRepository.find("name", "LABEL#01")).thenReturn(......);.
Assuming you're using only the PanacheQuery.page() and the PanacheQuery.list() methods something like this (not tested should work):
PanacheQuery query = Mockito.mock(PanacheQuery.class);
Mockito.when(query.page(Mockito.any()).thenReturn(query);
Mockito.when(query.list()).thenReturn(labels);
I'll open an issue on Quarkus, maybe we can do better (provide a MockQuery) or maybe we should at least document this.
Another solution would be to encapsulate the various calls you make to the PanacheQuery object in a dedicated method inside your entity and mock this one like in this example: https://quarkus.io/guides/hibernate-orm-panache#adding-entity-methods
For school purposes I am creating an application that's working with a stock API.
I am trying to write a test for a method that gets all the stock data of the last 10 years. Instead of actually getting all that data, I want to throw an exception.
The method I Want to test:
#Override
public List<StockData> getAllTeslaStockData() throws AlphaVantageException {
List<StockData> stockData;
AlphaVantageConnector apiConnector = new AlphaVantageConnector(APIKEY, TIMEOUT);
TimeSeries stockTimeSeries = new TimeSeries(apiConnector);
try {
Daily responseDaily = stockTimeSeries.daily("TSLA", OutputSize.FULL);
stockData = responseDaily.getStockData();
} catch (AlphaVantageException e) {
LOGGER.log(Level.SEVERE, "something went wrong: ", e);
throw e;
}
return stockData;
}
The stockTimeSeries.daily(....) call can throw the AlphaVantageException.
I've mocked the TimeSeries class like this:
TimeSeries stockTimeSeries = mock(TimeSeries.class);
In my test class I want to mock this call, and return an exception instead of actual data.
when(stockTimeSeries.daily("TSLA", OutputSize.FULL)).thenThrow(new AlphaVantageException("No stock data available"));
Regardless of how I am trying to mock this bit of code, it'll never throw the exception. It will always just execute the code, and return valid stock data, instead of throwing the exception like i've tried to do.
How can I mock this bit of code, so that itll throw the exception I am expecting for my tests.
The AlphaVantageConnector, TimeSeries and Daily classes are part of a library used to access the stock API, so I can't change these classes.
I am using JUnit 4.12 and Mockito to try and achieve this.
You can use thenThrow() method. Below is the example
#Test(expected = NullPointerException.class)
public void whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() {
MyDictionary dictMock = mock(MyDictionary.class);
when(dictMock.getMeaning(anyString()))
.thenThrow(NullPointerException.class);
dictMock.getMeaning("word");
The TimeSeries object is created in the method itself, so you can't mock it - mocking is intended to mock members.
What you can do is to do something like
class YourClass {
private Supplier<TimeSeries> seriesCreator = () -> {
return new TimeSeries(new AlphaVantageConnector(APIKEY, TIMEOUT));
}
which you use to create the series in your method
#Override
public List<StockData> getAllTeslaStockData() throws AlphaVantageException {
TimeSeries stockTimeSeries = seriesCreator.get();
Now you can mock that Supplier.
#Mock Supplier<TimeSeries> seriesCreatorMock;
#InjectMocks MyClass sut;
and in your test
#Test(expected = AlphaVantageException.class)
void testException() {
when(seriesCreatorMock.get()).thenThrow(new AlphaVantageException());
sut.getAllTeslaStockData()
}
EDIT: as suggested by Angkur in the comments, the clean way would be to
class SeriesCreator implements Supplier<TimeSeries> {
public TimeSeries get() {
return new TimeSeries(new AlphaVantageConnector(APIKEY, TIMEOUT));
}
}
class YourClass {
private Supplier<TimeSeries> seriesCreator = new SeriesCreator();
// ...
The code in the main class is creating a new instance of TimeSeries which it will use every time this method is called, so the mocked TimeSeries object is not getting used at all.
TimeSeries stockTimeSeries = new TimeSeries(apiConnector); // --> This is not getting mocked
try {
Daily responseDaily = stockTimeSeries.daily("TSLA", OutputSize.FULL);
stockData = responseDaily.getStockData();
}
You should create another method in your class (or even a separate class if it better satisfies the SOLID principles) which returns you the TimeSeries object. Something like:-
<access modifier> TimeSeries getTimeSeries(...) {
}
and then this method should be mocked in the Junit, and when mocked, it should return the Mocked TimeSeries reference (which is created in TimeSeries stockTimeSeries = mock(TimeSeries.class); ). You would need to use .spy() on the main class (unless you are using a different class to create TimeSeries object) in order to be able to mock the specific method getTimeSeries() but not the others.
MainClass mainObject = Mockito.spy(new MainClass());
Mockito.when(mainObject.getTimeSeries()).thenReturn(stockTimeSeries);
Then, the method call stockTimeSeries.daily() will get actually mocked by your existing code :
when(stockTimeSeries.daily("TSLA", OutputSize.FULL)).thenThrow(new AlphaVantageException("No stock data available"));
NOTE: you should also consider using .anyString() style methods provided by Mockito API while mocking.
Im helper method use ehcache, to reduce queries to Db. Now want to implement JUnit+Mockito test to ensure that ehcache works properly. Have such variant of test:
#Autowired
private DBService service;
#Autowired
private DiscountHelper discountHelper;
#Autowired
private CacheManager cacheManager;
#Before
public void setUp() throws Exception {
assertNotNull(cacheManager);
}
#Test
public void testGetDiscountWithCache() throws RuntimeException,
InterruptedException {
String id1 = "id1";
String id2 = "id2";
String id3 = "id3";
List<String> discountsId = new ArrayList<String>();
discountsId.add(id1);
discountsId.add(id2);
discountsId.add(id3);
List<Map<String, Object>> attrList = new ArrayList<Map<String, Object>>();
attrList.add(new Discount().getAttributes());
attrList.add(new Discount().getAttributes());
attrList.add(new Discount().getAttributes());
Cache cache = cacheManager.getCache(DiscountHelper.CACHE_NAME);
assertNotNull(cache);
assertEquals(0, cache.getSize());
// First run with empty cache
when(service.getAllItems(eq(Discount.TABLE_NAME))).thenReturn(attrList);
List<Discount> actualResult = discountHelper
.getAllDiscountsUsingCache();
assertNotNull(actualResult);
assertEquals(attrList.size(), actualResult.size());
verify(service).getAllItems(eq(Discount.TABLE_NAME));
cache = cacheManager.getCache(DiscountHelper.CACHE_NAME);
// In cache should be 1 record
assertNotNull(cache);
assertEquals(1, cache.getSize());
}
And test method is:
#Cacheable(cacheName = CACHE_NAME, refreshInterval = 1000 * 900, decoratedCacheType = DecoratedCacheType.REFRESHING_SELF_POPULATING_CACHE)
public List<Discount> getAllDiscountsUsingCache() throws RuntimeException,
InterruptedException {
List<Map<String, Object>> result = dbService
.getAllItems(Discount.TABLE_NAME);
List<Discount> discountList = new ArrayList<Discount>();
for (Map<String, Object> entry : result) {
discountList.add(new Discount(entry));
}
return discountList;
}
And this perfectly works. In test i`m sure that after invocation of method I get something in cache. As you can see I also verify that was called method getAllItems in db service. That is good for first time invocation. Next I add second invocation of discountHelper.getAllDiscountsUsingCache() in the same test like this:
when(service.getAllItems(eq(Discount.TABLE_NAME))).thenReturn(attrList);
actualResult = discountHelper
.getAllDiscountsUsingCache();
assertNotNull(actualResult);
assertEquals(attrList.size(), actualResult.size());
verify(service, times(0)).getAllItems(eq(Discount.TABLE_NAME));
So I just want to check that on second invocation there will not be calls to DB service via method getAllItems by this verify: verify(service, times(0)).getAllItems(eq(Discount.TABLE_NAME)); and result will be obtain from cache.
But it doesn't work, I still get invocation of DB method. I find this tutorial http://blog.goyello.com/2010/07/29/quick-start-with-ehcache-annotations-for-spring/ and try variant with delegate object for ehcache testing, but it still invoke db methods on test. What`s wrong?
By the way in production ehcache works good as I see in logs of tomcat, so this is a problem of test. Any suggestions how to fix it?
In the second invocation you use the same mock object (service) created (as I assume from a question's tag) by Springockito during the Spring context initialization. The mock remembers getAllItems() call from the first invocation. You can:
reset the mock before the second invocation using reset(service),
or
check after the second invocation) if there is still one (not two) getAllItems() invocation.
I'm starting some testing using Mockito on some service classes I use for connecting to my data store. I now want to determine the best practice way writing tests for it. The principle is for each entity there is a way to list, add, delete etc a row from the data store(mongo/mysql etc) for a specific entity.
Take this class that allows me to talk to my database that stores a list of companies
public class CompanyService extends Service{
public CompanyService() {
...
}
public saveCompany(Company company) {
...
}
// get a list of all companies
public List<Company> getCompanies() {
List<Company> companies = new ArrayList<Company>();
try {
CompanyResult<Rows<String, String>> rows = db.query(....);
for (Row<String, String> row : rows.getResult()) {
companies.add(row.getColumns());
}
catch (Exception e){
logger.warn("Error retrieving companies", e);
}
}
}
What exactly should I test in the getCompanies method and how can I use Mockito to do it?
Your System Under Test is the Company Service. You want to test that, assuming all its dependencies/collaborators function properly, it functions properly.
The db object looks like the only dependency/collaborator you need to worry about within the getCompanies() method. Use Mockito to mock the call to db.query()
You could set up a test method like so:
#Test
public void testGetCompanies() {
/*** Arraign ***/
CompanyService cs = new CompanyService();
// Setup mock db
DB mockDb = mock(DB.class);
// Setup fake results for query
CompanyResult<Rows<String, String>> sampleResults = ... // build sample results here
// Have query on mock return fake results
when(db.query(/* match arguments */)).thenReturn(sampleResults);
// Tell your System Under Test to use the mock collaborator
cs.setDB(mockDb);
/*** Act ***/
CompanyResult<Rows<String, String>> results = cs.getCompanies();
/*** Assert ***/
... // Test that results and sampleResults are effectively the same
}
You could test how your code would work if the db query returned and empty result,null or if row has null values or unexpected values. You could mock the db class to return these values. You could also mock the db class to throw an exception to see how your code could react.