DEV Community

Hauke T.
Hauke T.

Posted on

TypeScript Unit Tests: Access `private` Members

Disclaimer: This is not a lengthy discussion. But a small reference type post. There are other (lengthy) posts that go into the details. I like it short.

There is some ongoing debate about testing private members (methods, fields, properties, ...). In my opinion there are occasions where it is useful to do that.

It is not possible to directly inspect/test private members in languages like C#. But there is a common inheritance based workround, where private members are made protected.

In your test code you extend those classes and write wrappers/accessors to access these members. Then you actually test your derived class.

This is cumbersome and also changes the semantics of the class you want to test. private members appear to be intended to be accessed in derived classes. Which is not the case!


JavaScript/TypeScript does not require you to do that (at least for TypeScript private members, not for ES private (#) class fields).

// mod.ts
export class SomeClass {
    private _somePrivateProp = "foo";
}
Enter fullscreen mode Exit fullscreen mode

JavaScript does not care if your member is marked private by TypeScript.
The TypeScript compiler enforces that you don't access private members from outside the class using dot notation (inst.prop).
But it is possible to access the property using bracket notation (inst["prop"]).

// mod.test.ts
import {SomeClass} from "./mod.ts";
test("privatePropIsFoo", () => {
    const inst = new SomeClass();
    expect(inst._somePrivateProp).toBe("foo"); // TS2341: Property '_somePrivateProp' is private and only accessible within class 'SomeClass'.

    expect(inst["_somePrivateProp"]).toBe("foo"); // OK
})
Enter fullscreen mode Exit fullscreen mode

This is great because refactoring tools still work. And it saves a lot of redundant code.

But there is a caveat: jest.spy(inst, "_privateMethod") will not work, because TypeScript enforces that only public methods are spied on. The simplest workaround is to cast inst as any. Until there is a Utility Type that treats all members als public. As already suggested.

Top comments (0)