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
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

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
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

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Driving DevOps With Smart, Scalable Testing
  • Unit Testing Large Codebases: Principles, Practices, and C++ Examples
  • Practical Use of Weak Symbols
  • Generate Unit Tests With AI Using Ollama and Spring Boot

Trending

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • Advancing Your Software Engineering Career in 2025
  • Building a Real-Time Audio Transcription System With OpenAI’s Realtime API
  • Introducing Graph Concepts in Java With Eclipse JNoSQL
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Mock Private Method

Mock Private Method

By 
Lubos Krnac user avatar
Lubos Krnac
·
Feb. 12, 14 · Tutorial
Likes (12)
Comment
Save
Tweet
Share
158.2K Views

Join the DZone community and get the full member experience.

Join For Free

Foreword

If you already read some other blog post about unusual mocking, you can skip prelude via this link.

I was asked to put together examples for how to mock Java constructs well known for their testability issues:

  • Mock private method
  • Mock final method
  • Mock final class
  • Mock constructor
  • Mock static method

I am calling these techniques unusual mocking. I was worried that such examples without any guidance can be widely used by teammates not deeply experienced in mocking frameworks.

Developers practicing TDD or BDD should be aware of testability problems behind these constructs and try to avoid them when designing their tests and modules. That is the reason why you probably wouldn't be facing such unusual mocking often on project using these great programming methodologies.

But sometimes you have to extend or maintain legacy codebase that usually contains low cohesive classes. In most cases there isn't time in the current hectic agile world to make such classes easy to unit test the standard way. When you are trying to unit test such classes, you often realize that unusual mocking is needed.

That is why I decided to create and share refactoring considerations alongside with examples and workarounds for unusual mocking. Examples are using Mockito and PowerMock mocking frameworks and TestNG unit testing framework.

Mock Private Method

Refactoring Considerations

Private method that is needed to be mocked can be in:

  • testing class (will call it TC)
  • direct dependency of testing class (will call is DDC)
  • class that is not direct dependency of testing module (will call it NDDC)

Re-factoring techniques to consider:

  • If the private method is in TC, it is a good sign that TC has low cohesion (has too many responsibilities) and logic behind private method should be extracted into separate class. After this refactoring, private method in TC becomes public in new dependency class. Than it is possible to mock it standard way.
  • If the private method is in DDC, concerns of TC and DDC modules are not separated properly. It means you are trying to test some logic from DDC in test for TC. Consider moving this logic to TC or to separate module. Private method than becomes public and can be mocked standard way.
  • If the private method is in NDDC, you are probably creating integration test instead of unit test. Unit test in theory should be testing module in isolation. That means to mock all direct dependencies (sometimes it's easier to test with real objects when they are simple and independent enough). Consider:
    • Creation of unit test first. You can decide later if integration test is needed for group of modules you trying to test.
    • Find easier to mock boundaries for your integration test (you can find a clue in unit test for NDDC if exists)
    • Refactor NDDC according refactoring practises mentioned for TC and DDC above, update it's unit test (also all tests affected by refactoring), and use created public method as boundary for your integration test.

Workaround Using Mockito

This is my preferred technique when I need to mock private method. I believe that minor exposing of internal implementation in flavor to enhance testability of testing module is much lower risk for project than fall into bytecode manipulation mocking  framework like PowerMock or JMockIt.

This technique involves:

  • Changing private access modifier to default
  • Partially mock testing object by using spy

Mockito example covers:

  1. Mocking of changed default method with return value
  2. Mocking of changed changed default void method
  3. Verifying of changed default method calls

Class under test:

public class Train {
public int compose() {
for (int idx = 0; idx < getWagonsCount(); idx++) {
addWagon(0);
}
return getWagonsCount();
}

/**
 * Access modifier was changed from private to default to enhance
 * testability
 */
// private
int getWagonsCount() {
throw new UnsupportedOperationException("Fail if not mocked!");
}

/**
 * Access modifier was changed from private to default to enhance
 * testability
 */
// private
void addWagon(int position) {
throw new UnsupportedOperationException(
"Fail if not mocked! [position=" + position + "]");
}
}

Test:

@Test
public void testCompose() {
Train train = new Train();
Train trainSpy = Mockito.spy(train);

//notice different Mockito syntax for spy   
Mockito.doReturn(TESTING_WAGON_COUNT).when(trainSpy).getWagonsCount();
Mockito.doNothing().when(trainSpy).addWagon(0);


// invoke testing method
int actualWagonCount = trainSpy.compose();

Assert.assertEquals(actualWagonCount, TESTING_WAGON_COUNT);
Mockito.verify(trainSpy, Mockito.times(TESTING_WAGON_COUNT))
.addWagon(0);
}

Usage of PowerMock

Before usage of this example, please carefully consider if it is worth to bring bytecode  manipulation risks into your project. They are gathered in this blog post. In my opinion it should be used only in very rare and non-avoidable cases.

Test shows how to mock private method directly by PowerMock. Example covers:

  1. Mocking of private method with return value
  2. Mocking of private void method
  3. Verifying of private method calls

Class under test:

public class Truck {
public double addLoad(Collection<Double> boxWeightsToAdd) {
for (Double boxWeight : boxWeightsToAdd) {
addBoxToLoad(boxWeight);
}
return getLoadWeight();
}

private double getLoadWeight() {
throw new UnsupportedOperationException("Fail is not mocked!");
}

private void addBoxToLoad(double weight) {
throw new UnsupportedOperationException("Fail is not mocked! [weight="
+ weight + "]");
}
}

Test:

@PrepareForTest(Truck.class)
public class TruckTest extends PowerMockTestCase {
private static final double TESTING_LOAD_WEIGHT = 200;
private static final double TESTING_BOX_WEIGHT = 100;

@Test
public void testTestingMethod() throws Exception {
Truck truck = new Truck();
Truck truckSpy = PowerMockito.spy(truck);

PowerMockito.doReturn(TESTING_LOAD_WEIGHT).when(truckSpy,
"getLoadWeight");
PowerMockito.doNothing().when(truckSpy, "addBoxToLoad",
TESTING_BOX_WEIGHT);

// call testing method
Collection<Double> boxesWeights = Arrays.asList(TESTING_BOX_WEIGHT,
TESTING_BOX_WEIGHT);
double actualLoad = truckSpy.addLoad(boxesWeights);

Assert.assertEquals(actualLoad, TESTING_LOAD_WEIGHT);
PowerMockito.verifyPrivate(truckSpy, Mockito.times(2)).invoke(
"addBoxToLoad", TESTING_BOX_WEIGHT);
}
}

Links

Source code can be downloaded from Github.

Other unusual mocking examples:

  • Mock final method
  • Mock final class
  • Mock constructor
  • Mock static method


unit test

Opinions expressed by DZone contributors are their own.

Related

  • Driving DevOps With Smart, Scalable Testing
  • Unit Testing Large Codebases: Principles, Practices, and C++ Examples
  • Practical Use of Weak Symbols
  • Generate Unit Tests With AI Using Ollama and Spring Boot

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!