-1

Let's say I have the following typescript class:

class MyComponent {
  private something: number;

  constructor () {
    this.something = 0
    this.incrementSomething()
  }

  private incrementSomething () : number {
    return this.something++
  }
}

export default MyComponent

And my goal is to test it with jest, but I've got more questions then answers.

  • Is this a bad design pattern?
  • Should private methods be tested? (there are many opinions on the net, hard to decide)
  • Should I ignore jest coverage with this setup as it will report class as untested?
  • Should I create a public method instead and call my private method within it?

It is my first attempt to use private methods in typescript and try to test them, so please be patient :)

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Morpheus
  • 8,829
  • 13
  • 51
  • 77
  • Maybe I misunderstand how coverage is calculated, but in this case, the constructor calls the method, and thus the private code _will_ be tested when you instantiate your object during tests. – Pac0 Jun 06 '20 at 08:34
  • Yes, it will be called from constructor, but how the private method will be tested as part of initialization of a class? – Morpheus Jun 06 '20 at 08:37
  • 2
    opinion in favor of "public" testing only : Your class has exposed "behaviors", called by the "outside" and those are what matters. If you think a logic in a private method is sufficiently complex and important in your software to be tested, you should not make it public in the class (if it's not used outside, it makes no sense), but rather extract this logic in another class (static helper class or service or the like), where it makes sense that the method is public. – Pac0 Jun 06 '20 at 08:37
  • 1
    Everyone has opinions and that is why this question will accumulate. Mine is that `private` should not be used. – Aluan Haddad Jun 06 '20 at 08:37
  • 1
    @Morpheus : your example is very simple for demo purposes. So let's analyze its _behavior_. It seems that what happens is that there is a field `something`, and that its value is one after construction. So test this, that a `new MyComponent()` gives an object with `something === 1`. The fact that it uses a method "incrementSomething" is an implementation detail that is not important for this behavior. If the "incrementation logic" is used in many places, then it should be a public method in other class, as an example of what I told in my previous comment. – Pac0 Jun 06 '20 at 08:41
  • 2
    I agree with @AluanHaddad but I think both sides of the argument have their strengths; I don't think either is strictly correct. I think that this question should be updated to _only_ cover _how_ to test private methods; anything is likely to just be opinions – OliverRadini Jun 06 '20 at 08:46
  • @Pac0 makes sense now :) so for example if there were multiple private methods called from constructor, I shouldn't really test them even if one of the methods has some logic within? – Morpheus Jun 06 '20 at 08:46
  • @OliverRadini I can use https://www.npmjs.com/package/rewire to test private methods, however I am more interested if the private method called from constructor should be tested and if I should use `jest coverage` report at all in that case. – Morpheus Jun 06 '20 at 08:48
  • 2
    @Morpheus I understand, I'd recommend personally that you should indeed test private methods, I just think that SO is the wrong place for that kind of question; it's opinion based and might be better like [software engineering stack exchange.](https://softwareengineering.stackexchange.com/) – OliverRadini Jun 06 '20 at 08:49
  • Just to clarify, I only mean in TypeScript. There are several ECMAScript features being introduced that conceptually conflict with `private`. Furthermore, it provides a false sense of security because it is only design-time privacy. If you want actual privacy, use a closure. – Aluan Haddad Jun 06 '20 at 08:50
  • 1
    To clarify, I actually think it's a perfectly valid position to believe that private members are a bad idea in general, and that making something public for improved testability is a perfectly good reason to make something public, but there are lots of very valid opinions on this – OliverRadini Jun 06 '20 at 08:54
  • yep, opinion mostly here. I voted to close the question as such, – Pac0 Jun 06 '20 at 08:55
  • And to add to my suggestion, in this case I would advocate to have at least a public getter for `something` (but, hey, opinions/feeling again) – Pac0 Jun 06 '20 at 08:56
  • yeah, I thought that many answers would be mostly opinion based. Probably I am puzzled more with `jest coverage` reports, rather than `private` methods in `typescript` – Morpheus Jun 06 '20 at 09:00

1 Answers1

2

I don't think SO is an ideal place for this kind of question, as most of what you're asking is opinion based. You can however, assert that the object is any in order to do some testing:

class MyComponent {
  private something: number;

  constructor () {
    this.something = 0
    this.incrementSomething()
  }

  private incrementSomething () : number {
    return this.something++
  }
}

const thingIWantToTest = new MyComponent();

console.log((thingIWantToTest as any).something); // works
console.log(thingIWantToTest.something);          // type error
OliverRadini
  • 6,238
  • 1
  • 21
  • 46
  • I get `TS2349` and `TS2448` compile errors when trying this in test. – Morpheus Jun 06 '20 at 09:09
  • @Morpheus it works exactly as described: https://www.typescriptlang.org/play/?experimentalDecorators=true&ssl=17&ssc=30&pln=17&pc=39#code/MYGwhgzhAECyCeBhA9gWwA7IHYFMsBdoBvAWAChpLp0AnASwDcx8doI0d8ALOrAcwBc0LAFdUAIxw0A3OXJVowbBHw0RwfMhoAKAJTF5CqtzoQAdO1Sce-aAF5oABkNHoJ872A0cVggGUOE349F2gAXzkKKlpGZlZPb198AKsgvj0hUQkpAyjXb3wRGiw3HnNLa14+AGpq0IiyBvIlLBVSqoBJAHUwAgAVZD6cNodcAHc4JDRMXAI9WTJm5WQQHDMQZHTtNO7e-AGhtshoXvhdC0CbPl1paAB6O+gxrQBrCCXWlbWN9J2e-sGw3wF1SVxu0CAA – Aluan Haddad Jun 06 '20 at 09:11
  • @morpheus it sounds like you're trying to call a method of the class? – OliverRadini Jun 06 '20 at 09:14
  • yup, my bad :) I am going to accept your answer based on the comments you gave under the question and this solution. Thanks a lot :) – Morpheus Jun 06 '20 at 09:21
  • 1
    Also `thingIWantToTest['something']`. – Estus Flask Jun 06 '20 at 09:43
  • @EstusFlask Interesting! I'd never have expected that to work – OliverRadini Jun 06 '20 at 09:49