Typescript

How to write unit testing for Angular TypeScript for private methods with Jasmine

25 September 2026 · 7 min read

How to write unit testing for Angular  TypeScript for private methods with Jasmine

Writing effective unit tests is crucial for building robust and maintainable Angular applications. Testing private methods, however, presents a unique challenge. This post dives deep into how to write unit tests specifically for private methods in Angular using Jasmine and TypeScript, providing actionable strategies and real-world examples to elevate your testing game.

Why Test Private Methods?

While some argue against testing private methods directly, focusing instead on testing public interfaces, there are valid reasons for wanting granular control over testing private logic. Complex internal calculations, data transformations, or sensitive operations often reside within private methods. Testing these directly can pinpoint issues early in the development cycle and prevent regressions. Directly testing private methods allows for focused verification of individual functionalities, enhancing the overall quality and resilience of your codebase. This approach provides more comprehensive test coverage and facilitates quicker identification of bugs within intricate private logic.

Accessing Private Methods in Tests

TypeScript’s inherent privacy features can make accessing private methods directly in tests tricky. One approach is using the Reflect API. Reflect provides methods for interacting with object properties, even private ones. However, this approach has limitations and can raise potential maintainability concerns when refactoring. An alternative involves the use of a test double, such as a spy, that allows you to intercept and mock the private method’s behavior. This technique avoids direct access to the private method while still enabling focused unit testing of its logic. Choosing the right approach depends on the specific needs and complexity of your project.

Using Jasmine Spies for Private Method Testing

Jasmine spies offer a powerful way to test private methods without modifying production code. Spies allow you to track calls to a method, control its return value, and even replace its implementation entirely. By using a spy, you can isolate the private method’s behavior and verify its interactions with other parts of the class without altering the class structure itself. This ensures that your tests are focused and maintainable.

Here’s how you can create a Jasmine spy for a private method:

  1. Obtain a reference to the component instance.
  2. Use spyOn to create the spy: spyOn(componentInstance, 'privateMethodName' as any);.
  3. Control the spy’s behavior using .and.returnValue(), .and.callThrough(), or .and.callFake().

Example: Testing a Private Calculation Method

Let’s say you have a component with a private method calculateTotal(a: number, b: number): number. Here’s how you would test it using a Jasmine spy:

it('should calculate the total correctly', () => { spyOn(component, 'calculateTotal' as any).and.returnValue(10); expect(component.publicMethodThatCallsCalculateTotal()).toBe(10); }); 

This example demonstrates how to use a spy to intercept the calculateTotal method and control its return value. This approach effectively tests the private method’s functionality without requiring direct access.

  • Jasmine spies provide flexibility in controlling method behavior.
  • This technique maintains encapsulation and avoids code modification.

Consider this scenario: you’re developing a financial application with complex interest calculations handled within a private method. Thoroughly testing this private method ensures the accuracy and reliability of your application’s core functionality. Testing private methods can also be crucial when dealing with sensitive data handling or security-related operations.

Alternative Approaches and Considerations

While Jasmine spies are often the preferred method, other approaches exist. One alternative is to refactor the private method into a separate utility function or service, making it publicly testable. However, this approach can impact the component’s internal structure. Another consideration is whether testing through the public interface sufficiently covers the private method’s logic. If so, direct testing of the private method might be unnecessary. Ultimately, the best approach depends on the specific context of your project.

As stated by Robert C. Martin, “Clean code always looks like it was written by someone who cares.” Investing time in comprehensive testing, including testing private methods where appropriate, is a key aspect of writing clean and maintainable code.

For more in-depth information on unit testing in Angular, refer to the official Angular documentation (Angular Testing Guide). Explore resources like the Jasmine documentation (Jasmine Documentation) for further details on spies and other testing utilities. Also, Jest is another popular testing framework for JavaScript and provides similar functionalities.

Learn more about Angular unit testing best practices.Infographic Placeholder: [Insert infographic illustrating different approaches to testing private methods, highlighting pros and cons of each.]

  • Ensure complete test coverage for critical functionalities.
  • Choose the approach that best suits your project’s structure.

FAQ

Q: Is it always necessary to test private methods?
A: Not necessarily. If the public interface thoroughly exercises the private method’s logic, direct testing might be redundant. Prioritize testing critical and complex private logic.

Testing private methods in Angular requires careful consideration and the strategic use of tools like Jasmine spies. By mastering these techniques, you can significantly improve the quality, reliability, and maintainability of your Angular applications. Start implementing these strategies in your projects today for more robust and bug-free code. Explore advanced topics like asynchronous testing and mocking dependencies to further enhance your testing capabilities. Dive deeper into testing methodologies and best practices to build truly resilient Angular applications.

Question & Answer :
How do you test a private function in angular 2 ?

class FooBar { private _status: number; constructor( private foo : Bar ) { this.initFooBar(); } private initFooBar(){ this.foo.bar( "data" ); this._status = this.fooo.foo(); } public get status(){ return this._status; } } 

The solution I found

  1. Put the test code itself inside the closure or Add code inside the closure that stores references to the local variables on existing objects in the outer scope.

    Later strip out the test code using a tool. http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/

Please suggest me a better way to solve this problem if you have done any?

P.S

  1. Most of the answer for similar type of question like this one doesn’t give a solution to problem, that’s why I’m asking this question
  2. Most of the developer say you Don’t test private functions but I don’t say they are wrong or right, but there are necessities for my case to test private.

I’m with you, even though it’s a good goal to “only unit test the public API” there are times when it doesn’t seem that simple and you feel you are choosing between compromising either the API or the unit-tests. You know this already, since that’s exactly what you’re asking to do, so I won’t get into it. :)

In TypeScript I’ve discovered a few ways you can access private members for the sake of unit-testing. Consider this class:

class MyThing { private _name:string; private _count:number; constructor() { this.init("Test", 123); } private init(name:string, count:number){ this._name = name; this._count = count; } public get name(){ return this._name; } public get count(){ return this._count; } } 

Even though TS restricts access to class members using private, protected, public, the compiled JS has no private members, since this isn’t a thing in JS. It’s purely used for the TS compiler. Therefor:

  1. You can assert to any and escape the compiler from warning you about access restrictions:

    (thing as any)._name = "Unit Test"; (thing as any)._count = 123; (thing as any).init("Unit Test", 123); 
    

    The problem with this approach is that the compiler simply has no idea what you are doing right of the any, so you don’t get desired type errors:

    (thing as any)._name = 123; // wrong, but no error (thing as any)._count = "Unit Test"; // wrong, but no error (thing as any).init(0, "123"); // wrong, but no error 
    

    This will obviously make refactoring more difficult.

  2. You can use array access ([]) to get at the private members:

    thing["_name"] = "Unit Test"; thing["_count"] = 123; thing["init"]("Unit Test", 123); 
    

    While it looks funky, TSC will actually validate the types as if you accessed them directly:

    thing["_name"] = 123; // type error thing["_count"] = "Unit Test"; // type error thing["init"](0, "123"); // argument error 
    

    To be honest I don’t know why this works. This is apparently an intentional “escape hatch” to give you access to private members without losing type safety. This is exactly what I think you want for your unit-testing.

Here is a working example in the TypeScript Playground.

Edit for TypeScript 2.6

Another option that some like is to use // @ts-ignore (added in TS 2.6) which simply suppresses all errors on the following line:

// @ts-ignore thing._name = "Unit Test"; 

The problem with this is, well, it suppresses all errors on the following line:

// @ts-ignore thing._name(123).this.should.NOT.beAllowed("but it is") = window / {}; 

I personally consider @ts-ignore a code-smell, and as the docs say:

we recommend you use this comments very sparingly. [emphasis original]