Wrote a #Testcontainers test in Junit 5 with Springboot 3. The test runs and passes, but I have the following warning:
'MySQLContainer<SELF>' used without 'try'-with-resources statement
But the code shows in fact the container is NOT used outside the try with resources statement:
#Testcontainers
public class PageTemplateCreationTestContainerTests {
private static final Logger logger = LoggerFactory.getLogger(PageTemplateCreationTestContainerTests.class);
#Test
void mySQLContainerShouldBeRunning() {
try (
var mySQLContainer = new MySQLContainer<>("mysql:8.0")
.withLogConsumer(new Slf4jLogConsumer(logger))
) {
mySQLContainer.start();
assertThat(mySQLContainer.isRunning(), is(true));
}
}
}
I read through the docs for Autocloseable and of course there's no help here from IntelliJ. Thought maybe it was choking on the var syntax but no.
This warning should not appear.
TL;DR: It's a false positive due to the .withLogConsumer() chained call.
IntelliJ shows you that new MySQLContainer<>("mysql:8.0") is not closed by the try-with-resources block. Instead, you are calling .withLogConsumer(new Slf4jLogConsumer(logger)) on it and closibg that using try-with-resources.
Since closing the object returned by .withLogConsumer(new Slf4jLogConsumer(logger)) also closes the MySQLContainer (it is the same objects as it returns this, this is a false positive.
If you want to get around this error without suppressing it, you could try to close both resources (which is what IntelliJ wants from you):
try (
var containerWithoutLogger = new MySQLContainer<>("mysql:8.0");
var mySQLContainer = containerWithoutLogger.withLogConsumer(new Slf4jLogConsumer(logger))
) {
mySQLContainer.start();
assertThat(mySQLContainer.isRunning(), is(true));
}
However, this would close it twice. Alternatively, you could try to call withLogConsumer inside the try-block but that might result in a similar warning being shown at that point.
try (
var mySQLContainer = new MySQLContainer<>("mysql:8.0");
) {
mySQLContainer.withLogConsumer(new Slf4jLogConsumer(logger));
mySQLContainer.start();
assertThat(mySQLContainer.isRunning(), is(true));
}
Related
I have a DropWizard project with 2 database connections: one MySql and one Oracle (v11). The MySql connection and queries work just fine. I'm not getting any data from my Oracle queries and there are no errors in my logs.
My DOA looks like this:
public interface DummyDao {
#SqlQuery(
"select prod_sku, initial_qty, current_qty" +
" from prod_detail" +
" where prod_sku = :skuNumber")
#Mapper(DummyMapper.class)
Dummy getSku(#Bind("skuNumber") String skuNumber);
}
My mapper looks like this. When I added log statements to the mapper, I was able to verify it is never called.
public class DummyMapper implements ResultSetMapper<Dummy> {
public Dummy map(int index, ResultSet r, StatementContext ctx)
throws SQLException {
return new Dummy(
r.getString("prod_sku"),
r.getLong("initial_qty"),
r.getLong("current_qty"));
}
}
The DAO is being initialized in my application's run method via the following code:
public class ProductServiceApplication extends Application<ProductServiceConfiguration> {
DataSource sb_ds;
DBI sb_dbi;
DummyDao dummyDao;
#Override
public void run(
final ProductServiceConfiguration configuration,
final Environment environment) {
sb_ds = configuration.getSbliveDataSourceFactory()
.build(environment.metrics(), "sblive");
sb_dbi = new DBI(sb_ds);
dummyDao = sb_dbi.onDemand(DummyDao.class);
}
}
In order to verify there's nothing wrong with my connection, I temporarily added the following code to my run method and it returns the expected result:
try (Handle h = sb_dbi.open()) {
List<Map<String,Object>> result =
h.select("select initial_qty, current_qty from prod_detail where prod_sku = '10501034520008'");
System.out.println("bootstrap: " + result.toString());
}
Executing my DAO's getSku method with the same parameter returns null.
Can someone tell me what I'm doing wrong or point me to measures I can take to figure out what's causing this? I tried to debug it, but I simply don't know enough about JDBI internals to make any sense of what I'm looking at.
I found the issue. The problem is that the column associated with the bind variable is defined as CHAR(20) -- not VARCHAR(20) -- and the actual parameter value has a length of 14. When I execute the statement directly (using the handle or from SqlDeveloper), it works fine. But when using a prepared statement and bind variables, it's broken.
Padding the parameter out to 20 characters resolves the issue.
i am new to writing junits.I have my below java api which gets a unique value every time from database.It contains just a single query.I need to write junit for below api.can anybody give some suggestions how should i approach??
public static int getUniqueDBCSequence() throws Exception
{
int w_seq = 0;
QueryData w_ps = null;
ResultSet w_rs = null;
try
{
w_ps = new QueryData("SELECT GETUNIQUENUMBER.NEXTVAL FROM DUAL");
w_rs = SQLService.executeQuery(w_ps);
while ( w_rs.next() )
{
w_seq = w_rs.getInt(1);
}
}
catch (Exception a_ex)
{
LOGGER.fatal("Error occured : " + a_ex.getMessage());
}
finally
{
SQLService.closeResultSet(w_rs);
}
return w_seq;
}
You are using only static methods : in the class under test but also in the dependencies of it.
It is really not a testable code with JUnit.
Besides, what you do you want to test unitary ?
Your test has no substantive logic.
You could make SQLService.executeQuery() a method instance to be able to mock it. But really which interest to mock it ?
To assert that the result is returned w_seq = w_rs.getInt(1); ?
It looks like technical assertions that have few value and maintaining unit tests with few value should be avoided.
Now, you could test with DBunit or tools to populate a in memory database and executes the code against.
But the query executed have a strong coupling with Oracle sequences.
So, you could have some difficulties to do it.
I have a void method and I want to test it. How do I do that?
Here's the method:
public void updateCustomerTagCount() {
List<String> fileList = ImportTagJob.fetchData();
try {
for (String tag : fileList) {
Long tagNo = Long.parseLong(tag);
Customer customer = DatabaseInterface.getCustomer(tagNo);
customer.incrementNoOfTimesRecycled();
DatabaseInterface.UpdateCustomer(customer);
}
} catch(IllegalArgumentException ex) {
ex.printStackTrace();
}
}
when the method returns void, you can't test the method output. Instead, you must test what are the expected consequences of that method. For example:
public class Echo {
String x;
public static void main(String[] args){
testVoidMethod();
}
private static void testVoidMethod() {
Echo e = new Echo();
//x == null
e.voidMethod("xyz");
System.out.println("xyz".equals(e.x)); //true expected
}
private void voidMethod(String s) {
x = s;
}
}
It might not be always true, but basic concept of unit test is to check if function works as expected and properly handling errors when unexpected parameters/situation is given.
So basically unit test is against the functions that takes input parameters and return some output so we can write those unit test.
The code like yours, however, includes some other dependency (database call) and that's something you can't execute unless you write integration-test code or real database connection related one and actually that's not recommended for unit test.
So what you need to do might be introducing unit test framework, especially Mockto/Powermock or some other stuff that provides object mocking feature. With those test framework, you can simulate database operation or other function call that is going to be happening outside of your test unit code.
Also, about how do I test void function, there is nothing you can with Assert feature to compare output since it returns nothing as you mentioned.
But still, there is a way for unit test.
Just call updateCustomerTagCount() to make sure function works. Even with just calling the function, those unit test can raise your unit test coverage.
Of course for your case, you need to mock
ImportTagJob.fetchData();
and
DatabaseInterface.getCustomer(tagNo);
and have to.
Let mocked
ImportTagJob.fetchData();
throw empty list as well as non-empty list and check if your code works as you expected. Add exception handling if necessary. In your code, there are two condition depends on whether fieList are null or non-null, you need to test it.
Also, mock those objects and let them throw IllegalArgumentException where you expect it to be thrown, and write an unit test if the function throws a exception. In Junit, it should be like
#Test(expected = IllegalArgumentException.class)
public void updateCustomerTagCountTest(){
// mock the objects
xxxxx.updateCustomerTagCount();
}
That way, you can ensure that function will throw exception properly when it has to.
I am in a project now that is using JUnit as a framework to test engineering data (ref: last question Creating a Java reporting project -- would like to use JUnit and Ant but not sure how)
Since a picture (err a code block) tells a 1,000 words, so let me paste my loop:
JUnitCore junit = new JUnitCore();
RunListener listener = new RunListener();
junit.addListener(listener);
[...]
for (AbstractFault fault : faultLog) {
theFault = fault;
Result result = junit.run(GearAndBrakeFaultLogReports.class);
for (Failure f : result.getFailures()) {
output.println(log.getName());
output.println(fault.getName());
output.println(HelperFunctions.splitCamelCase(f.getDescription()
.getMethodName()));
output.println(f.getMessage());
output.println();
}
}
As you can see, I am running the "junit.run" many times (for each fault in the log).
However, if any one of my tests fires a fail() I don't want to repeat that test. In other words, if there are 50 faults in a log, and in fault #1 a test fails, I don't want to attempt that test in the 49 future faults I am looping through.
Here is an example test:
private static boolean LeftMLGDownTooLongFound = false;
#Test
public final void testLeftMLGDownTooLong() {
if (!LeftMLGDownTooLongFound
&& handleLDGReportFaults(false)
&& theFault.getName().equals(FaultNames.LDG_LG_DWN_TIME.toString())) {
assertNotGreater(getPCandRecNum(), 8f, ldgFault.getLeftStrutUpTime());
LeftMLGDownTooLongFound = true;
}
}
Currently, do to this, I am making a static bool that is set to false at first, but switches to true after the first assertion. Not sure if this works, but its the idea. I don't want to do this for every single test (100's of them).
Is there any public function, method, or way in the JUnitCore or Runner class that I can flag it so a test never runs more than once after a fail() is called?
Ah, figured it out. To do this, I need to implement a way to find the failed tests, then in the #Before area, ax out of the test. Here is what I added.
#Rule public TestName name = new TestName();
#Before
public void testNonFailedOnly() {
Assume.assumeTrue(!failedTests.contains(name.getMethodName()));
}
private static List<String> failedTests = new ArrayList<String>(256);
#Rule
public TestWatcher watchman = new TestWatcher() {
/* (non-Javadoc)
* #see org.junit.rules.TestWatcher#failed(java.lang.Throwable, org.junit.runner.Description)
*/
#Override
protected void failed(Throwable e, Description description) {
super.failed(e, description);
failedTests.add(description.getMethodName());
}
};
It does add about 1.5 seconds of overhead, which sucks... but better than the alternative!!
Anyone have ideas on how to optimize this? I believe the overhead is from the TestWatcher, don't think it from the arraylist.
I used a Java Class that every test extends.
In the #Before of this class I set a boolean hasPassed = false;
At the end of every #Test method I set this variable hasPassed = true;
In the #AfterMethod you can then check the variable.
If your test causes an exception, it wont reach the end and the variable is still false.
I'm verifying that a function was called using Mockito, but Mockito is telling me that the function I'm verifying was never called and that other functions were called. But it seems to me that I'm calling the right function...
Here's the stack trace for the error I'm getting:
Wanted but not invoked:
relationshipAutoIndexer.getAutoIndex();
-> at org.whispercomm.manes.server.graph.DataServiceImplTest.testInitIndices(DataServiceImplTest.java:117)
However, there were other interactions with this mock:
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:136)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:144)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:148)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:149)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.initIndices(DataServiceImpl.java:121)
at org.whispercomm.manes.server.graph.DataServiceImplTest.testInitIndices(DataServiceImplTest.java:117)
It occurs at
verify(relAutoIndexer).getAutoIndex();
of the test class code shown below.
Here is my code (I have a tendency to leave things out by accident. Please ask me for any code you think I'm missing and I'll add it):
public DataServiceImpl(GraphDatabaseService graphDb) {
super();
this.graphDb = graphDb;
unarchivedParent = new UnarchivedParent(graphDb.createNode());
archivedParent = new ArchivedParent(graphDb.createNode());
packetParent = new PacketParent(graphDb.createNode());
userParent = new UserParent(graphDb.createNode());
this.initIndices();
}
/**
* Initializes the node and relationship indexes.
*
* Updates the set of indexed properties to match {#link DataServiceImpl}
* .NODE_KEYS_INDEXABLE and {#link DataServiceImpl}.REL_KEYS_INDEXABLE.
*
* Note: auto indices can also be configured at database creation time and
* just retrieved at runtime. We might want to switch to that later.
*/
private void initIndices() {
/* Get the auto-indexers */
AutoIndexer<Node> nodeAutoIndexer = this.graphDb.index()
.getNodeAutoIndexer();
AutoIndexer<Relationship> relAutoIndexer = this.graphDb.index()
.getRelationshipAutoIndexer();
this.updateIndexProperties(nodeAutoIndexer,
DataServiceImpl.NODE_KEYS_INDEXABLE);
this.nodeIndex = nodeAutoIndexer.getAutoIndex();
this.updateIndexProperties(relAutoIndexer,
DataServiceImpl.REL_KEYS_INDEXABLE);
this.relIndex = relAutoIndexer.getAutoIndex();
}
/**
* Sets the indexed properties of an {#link AutoIndexer} to the specified
* set, removing old properties and adding new ones.
*
* #param autoIndexer
* the AutoIndexer to update.
* #param properties
* the properties to be indexed.
* #return autoIndexer, this given AutoIndexer (useful for chaining calls.)
*/
private <T extends PropertyContainer> AutoIndexer<T> updateIndexProperties(
AutoIndexer<T> autoIndexer, Set<String> properties) {
Set<String> indexedProps = autoIndexer.getAutoIndexedProperties();
// Remove unneeded properties.
for (String prop : difference(indexedProps, properties)) {
autoIndexer.stopAutoIndexingProperty(prop);
}
// Add new properties.
for (String prop : difference(properties, indexedProps)) {
autoIndexer.startAutoIndexingProperty(prop);
}
// Enable the index, if needed.
if (!autoIndexer.isEnabled()) {
autoIndexer.setEnabled(true);
}
return autoIndexer;
}
And here's the code for the test class:
#Before
public void setup() {
nA = mock(Node.class);
nB = mock(Node.class);
packetA = new PacketWrapper(nA);
packetB = new PacketWrapper(nB);
RelA = mock(Relationship.class);
RelB = mock(Relationship.class);
graphDb = mock(GraphDatabaseService.class);
nodeAutoIndexer = (AutoIndexer<Node>) mock(AutoIndexer.class);
relAutoIndexer = mock(RelationshipAutoIndexer.class);
}
#After
public void tearDown() {
packetA = null;
packetB = null;
}
/*
* ---------------- Test initIndices() ---------------
*/
//TODO
#Test
public void testInitIndices() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(indexManager.getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);
dataService = new DataServiceImpl(graphDb);
verify(nodeAutoIndexer, atLeastOnce()).getAutoIndex();
verify(relAutoIndexer).getAutoIndex();
}
Mockito, till version 1.8.5, had a bug in the case of polymorphic dispatch. It was fixed and is available in the first release candidate of the version 1.9.0. See issue 200.
So how does it happen in your code base. Note you are mocking these two classes
nodeAutoIndexer = (AutoIndexer<Node>) mock(AutoIndexer.class);
relAutoIndexer = mock(RelationshipAutoIndexer.class);
AutoIndexer happen to be a generic parent interface, in this interface there is this method ReadableIndex<T> getAutoIndex(). RelationshipAutoIndexer is a subtype of the AutoInexer where the generic part is fixed to Relationship, and override the getAutoIndex() method to return the covariant type ReadableRelationshipIndex.
See AutoIndexer and RelationshipIndexer.
Well, in your calling code you have these lines:
AutoIndexer<Node> nodeAutoIndexer = this.graphDb.index().getNodeAutoIndexer();
AutoIndexer<Relationship> relAutoIndexer = this.graphDb.index().getRelationshipAutoIndexer();
this.nodeIndex = nodeAutoIndexer.getAutoIndex();
this.relIndex = relAutoIndexer.getAutoIndex();
Both nodeAutoIndex in your production code and the mock nodeAutoIndexer in your test code have a reference of type AutoIndexer<Node>, so there's no problem regarding polymorphic dispatch.
However relAutoIndex in your production code is referenced by the type AutoIndexer<Relationship> and the mock relAutoIndexer in your test code is referenced by the type RelationshipAutoIndexer, so the wrong call is registered on the mock and then fails verification.
Your solution is either to upgrade the mockito version; the 1.9.0 RC1 is very stable and a final release should be coming your way. Or you can migrate your reference type (in your production code) from :
AutoIndexer<Relationship> relAutoIndexer = this.graphDb.index().getRelationshipAutoIndexer();
to :
RelationshipAutoIndexer relAutoIndexer = this.graphDb.index().getRelationshipAutoIndexer();
A few other remarks.
You don't actually need to write an after method here as JUnit creates a new instance on each method run, so your method just adds code that will be done anyway. Note this isn't the case with TestNG.
Instead of creating your mocks in the before method, you might want to use Mockito annotations. Don't forget the runner.
For example :
#RunWith(MockitoJUnitRunner.class)
public class YourTest {
#Mock SomeType someTypeMock;
// ...
}
The stubbing code is a bit ugly for several reasons.
Your should write consistent stubs.
Why not write this in a cleaner way; for example referencing indexManager in both case :
IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(indexManager.getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(indexManager.getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);
Or don't reference it at all
IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(graphDb.index().getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);
Also having a mock that returns a mock is usually a sign of design smell. You are breaking the law of Demeter, and breaking it means you will experience difficult testing, bad maintainability, and difficult evolution. When I say that you could hear me whisper also (without the syllogisms) : it will cost you money. Don't write legacy code! If you are practicing TDD or BDD, you will identify these issues at design time for your own code, which is great to prevent them.
However if you are dealing with legacy code, you can use this deep stubs syntax :
Using the static methods you could write this
GraphDatabaseService graphdb = mock(GraphDatabaseService.class, RETURNS_DEEP_STUBS);
Or using the annotation you could write this :
#Mock(answer = RETURNS_DEEP_STUBS) GraphDatabaseService graphdb;
And the stubbing :
when(graphDb.index().getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);