DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • You’ve Got Mail… and It’s a SPAM!
  • Revolutionizing Algorithmic Trading: The Power of Reinforcement Learning
  • The Role of AI and Programming in the Gaming Industry: A Look Beyond the Tables
  • How To Use Pandas and Matplotlib To Perform EDA In Python

Trending

  • You’ve Got Mail… and It’s a SPAM!
  • Revolutionizing Algorithmic Trading: The Power of Reinforcement Learning
  • The Role of AI and Programming in the Gaming Industry: A Look Beyond the Tables
  • How To Use Pandas and Matplotlib To Perform EDA In Python
  1. DZone
  2. Data Engineering
  3. Databases
  4. Effective Testing around Hibernate/ORM layer

Effective Testing around Hibernate/ORM layer

Amar Mattey user avatar by
Amar Mattey
·
Apr. 14, 14 · Interview
Like (0)
Save
Tweet
Share
9.21K Views

Join the DZone community and get the full member experience.

Join For Free
As applications that use Hibernate or any ORM frameworks grow complex, lots of performance issues don't get enough attention until it is too late. This article accounts for SLA time as part of the junits and allows developers to think in terms of calculating the number of calls hibernate is going to make in the background. This allows for developers to deal with facts rather than assumptions. 

Assuming we are doing TDD, let's build up the TestCase first.
We are going to build up a typical API to create Person with bunch of addresses.
To understand how this works, we will create a buggy Service and include background Audit mechanism, to simulate abstraction to developer.

 
@RunWith(SpringJUnit4ClassRunner.class)
public class PersonServiceTest {
  @Autowired
  private PersonService personService;

  @Before
  public void insertData() {
    TestUtil.createTestData(personService);
  }

  @Before
  public void cleanup() {
    QueryCountHolder.clear();
  }

  @Test(timeout = 500)
  public void testAddressCount() {
    assertThat(QueryCountHolder.getGrandTotal().getTotalNumOfQuery(), is(0));
    assertThat(personService.getAddressCount("John"), is(2));
    assertThat(QueryCountHolder.getGrandTotal().getTotalNumOfQuery(), is(1));
  }

  @Test(timeout = 500)
  public void testUpdatePerson() throws Exception {

    assertThat(QueryCountHolder.getGrandTotal().getTotalNumOfQuery(), is(0));

    Person person = personService.getCustomerByName("John");
    assertThat(person.getGender(), CoreMatchers.nullValue());
    person.setGender("Male");

    QueryCountHolder.clear();
    personService.save(person);
    assertThat(QueryCountHolder.getGrandTotal().getTotalNumOfQuery(), is(3));

    person = personService.getCustomerByName("John");
    assertThat(person.getGender(), CoreMatchers.is("Male"));
  }
}

testAddressCount - Based on the service interface, this test case assume 1 sql is executed to get the count of addresses give a first name 
testUpdatePerson - We update the person gender, and assume 3 sqls are executed.
  1. To read the person
  2. Update gender
  3. Audit event to record gender change
Both the test fails 
testAddressCount java.lang.AssertionError:  Expected: is <1> got: <2>
testUpdatePerson java.lang.AssertionError:  Expected: is <3> got: <4>

Let's dive deep into the service and see what is wrong.  
@Service
public class PersonServiceImpl implements PersonService {
  @Autowired
  private PersonRepository repository;

  @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
  public int getAddressCount(String firstName) {
    List<Person> list = repository.findByFirstNameLike(firstName);
    if (list == null) {
      return 0;
    }
    Person byFirstNameLike = list.get(0);
    return byFirstNameLike == null ? 0 : byFirstNameLike.getAddresses().size();
  }

  @Transactional(readOnly = false, propagation = Propagation.SUPPORTS)
  public Person save(Person person) {
    // un intended operation
    person.setLastName(person.getLastName() + " 1");
    return repository.save(person);
  }
}


As you can see in getAddressCount, instead of writing a custom hql, the developer did an mistake of reading object and doing a size on the list. The correct way of writing this method is to make use of custom query which does a count(*) on address table. 

Similarly with Save, the test expected to update Gender, but the service was doing something more than expected, triggering a unexpected audit record on last name. 

To demonstrate this article I have made use of datasource-proxy which is very good API to capture sqls that hibernate or any other ORM frameworks execute under the hood. 

Also, I feel like it is very good practice to use @Test(timeout) so we know if some one changes a method later on, and hinder the SLA.
Database

Opinions expressed by DZone contributors are their own.

Trending

  • You’ve Got Mail… and It’s a SPAM!
  • Revolutionizing Algorithmic Trading: The Power of Reinforcement Learning
  • The Role of AI and Programming in the Gaming Industry: A Look Beyond the Tables
  • How To Use Pandas and Matplotlib To Perform EDA In Python

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: