1

I have a method that calls another method to retrieve data and insert it into the database, how can I test this method in Junit since this method retrieve nothing? Can anyone provide me some example of this situation?

public static void method(){ 
    User user = getUser();  
    try {
        String Query = "INSERT INTO users (USER_ID , Name) VALUES ("
         +user.getID()+","+user.getName()+")";

        Statement statement = conn.createStatement();
        statement.executeUpdate(Query);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I was thinking to use mock object for user, but I'm not sure how can I check if the user is inserted to the database. please help.

user9434613
  • 89
  • 2
  • 6
  • 1
    assuming the database connection is an injected dependency abstraction, you can mock the dependency and verify that it is called/invoked when the method under test is exercised. done – Nkosi Mar 04 '18 at 17:48
  • "Mock" was going to be my answer. I've also seen database testing done with a real database, with part of ACID turned off, so that a transaction can be started, tested (isolation turned off so you can read the results outside of a transaction), and then the transaction rolled back instead of committed to return the test database to its original test state. I forget the parameter passed to the DB to put it in this state though. – markspace Mar 04 '18 at 18:06
  • *"I've also seen database testing done with a real database, with part of ACID turned off,[...] I forget the parameter passed to the DB to put it in this state"* forget about that. You should not do this. As mentioned by the others `unit tests` should not access a real database and other test types are easier to set up if run against a database in a virtual maschine you can reset as a whole after the tests are done. – Timothy Truckle Mar 05 '18 at 06:22

2 Answers2

1

There are few pointers here but before that, you have to be sure about what's the code under test. The reason I say this is because that will actually make you refactor your code a lot.

For example, for the code below:

public static void method(){ 
    User user = getUser();  
    try {
        String query = "INSERT INTO users (USER_ID , Name) VALUES ("
         +user.getID()+","+user.getName()+")";

        Statement statement = conn.createStatement();
        statement.executeUpdate(query);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

you might want to test following:-

  1. Whether the query string is created properly i.e. a valid SQL as expected?

  2. Should the method never throw an exception as we want to catch all the checked exception?

  3. All the resources are closed once the work is done? e.g. in your method connection is opened but never closed.

Now out of above points, there could be some points with higher importance e.g. ensuring query is built correctly.

So, for that, the query builder code should be pulled out of this method and now you could easily test this query in the separate unit test.

Similarly, you would want to make sure a connection is closed after its job is completed. Hence, you might want to extract this code to a method that accepts a query as param, open connection, performs DB CRUD closes the connection and returns the output. And make sure that you are not repeating this code all the time in different methods.

Now, let's go to the pointers:-

  1. If you at any point think that there is some code inside a method that's not testable till that code is part of the method. Please pull it out to a public / private method and test it.

  2. Never try to test DB persistence as part of a unit test. The DB drivers etc are already having their own tests and are globally used.

  3. If you think your method needs to be tested for whether it is called as many times as expected (it's what you want to test). It's called interaction based testing

You could use mocking (Mockito) and stub out the method under test and then assert how many times the method should be called. See this and this link.

Hope it helps!

Vinay Prajapati
  • 7,199
  • 9
  • 45
  • 86
0

Classes should be tested against the expected behavior.
Here testing the return type (even if it had other thing as void) makes no sense.

Your method performs a SQL query.
So your unit test has to assert the expected side effect on the database : an insertion with the expected values.
Note that to have reproducible and fast tests, you should favor embedded databases for unit testing.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • 1
    I personally disagree! a database interaction should never be tested there in unit testing and rather mocked. Until unless there is a customized logic for interaction with a database. Why would someone like to test the obvious thing that's going to work in unit testing? There are other tests e.g. E2E and integration tests to ensure such integrations are working fine. – Vinay Prajapati Mar 04 '18 at 18:49
  • Thank to express kindly your opinion despite the divergence : ) Integration tests are designed to test integration between components. As I code a component that performs queries I also want validate it unitary. Note that fast unit testing is one of the main goals of embedded databases. – davidxxx Mar 04 '18 at 18:59
  • 1
    From my experience, I have observed that using embedded databases and then test for object persisted properly etc just adds more efforts in writing unit tests while the fact is my unit under test is operating on a different database now. For example, suppose there is a feature that only originally used database supports and the embedded database doesn't what's going to happen with your unit test case is a reality missed out. Again this is my opinion and a practice that I follow. There are choices to be made in different situations when to go for embedded db and when not to. Thanks! – Vinay Prajapati Mar 04 '18 at 19:07
  • 1
    In fact it depends really on your requirement. If you have PL/SQL or similarly proprietary things, yes writing unit test for DAO or repository may be complicated. But in other cases, it should not be. Note that in memory databases as H2 provides some compatibility features with other DMS http://www.h2database.com/html/features.html. Testing a component only in integration may give false positive results because of side effects between component invocations. That's why unitary testing a component matters. – davidxxx Mar 05 '18 at 09:37