0

I have a private function outside component. It sounds more convenient to do test for function alone better than test it inside MyComponent, but it's private not exported.

function func(){
 return something;
}

export default class MyComponent extends Component {

render <SomeComponent someProp={func()} />
}

I use mocha and enzyme for test and I wonder if there is anyway to test private function rather than test it inside the component.

Jalal
  • 3,308
  • 4
  • 35
  • 43
  • Yeah, export it? – Anas Sep 06 '18 at 14:10
  • you missing the point here, in this case you are removing the concept of private functions – Jalal Sep 06 '18 at 14:11
  • 1
    You can't test private functions, and they're not supposed to be tested in isolation as they're supposed to be part of the internal implementation. – Anas Sep 06 '18 at 14:15
  • 1
    Possible duplicate of [unit testing of private functions with mocha and node.js](https://stackoverflow.com/questions/22097603/unit-testing-of-private-functions-with-mocha-and-node-js) – Anas Sep 06 '18 at 14:18
  • it's not duplicated since it has react component being used and there must some smart solution to test the function maybe through component instance. First you suggested to export it, then not testing it and now you refer to it as duplicated. I am not sure if you trying to help here! – Jalal Sep 06 '18 at 14:26
  • 1
    If you want to test it in isolation, then export it. If you think it's private and should not be exported, then you need to test through your other code. I don't see how React can help you with that or is linked to the problem. And Yes I'm trying to help. otherwise I won't be looking at your question. – Anas Sep 06 '18 at 14:30
  • well, there's a tag and example related to react – Jalal Sep 06 '18 at 14:38

2 Answers2

3

func is defined in module scope. It's not possible to reach variables outside the scope they were defined in JavaScript.

Even if func were exported, it would be impossible to provide proper unit tests for it, i.e. test func in one test, then test a unit depends on func (MyComponent) in another test with func being mocked/spied. func is referred within the module, its calls cannot be spied or stubbed.

In order to be fully testable, func needs to be either class method, this makes sense if func and MyComponent are related. Or move func to another module. In this case it's possible to mock the module, or as explained in this answer, due to how ES modules work, func import could be mocked/spied on module * import.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • agree with making func as class method which makes sense but i was trying to keep the logic outside the component, which turns out it is test headache – Jalal Sep 06 '18 at 15:23
  • 2
    Yes. On the other hand, if it isn't strictly tied to current class and may be used outside the class then it doesn't deserve to be a part of this module, that's what common testability concerns suggest. – Estus Flask Sep 06 '18 at 15:29
  • You can export the function and test it directly by destructuring your import. I've included an example below. – dysfunc Sep 06 '18 at 16:12
  • 1
    @dysfunc You won't be able to spy or mock `func` this way. Btw, it's no longer can be called 'private', because it's not. – Estus Flask Sep 06 '18 at 16:17
  • That's also not true. You can import the module using `*` which outputs the module object `import * as MyComponent from './myComponent';` and then you can `spy` or `stub` the method from there `someLib.spy(MyComponent, 'func')` – dysfunc Sep 06 '18 at 16:28
  • @dysfunc This won't work if `func` is referred directly inside same module like in this case. There will be a spy but it won't be called. – Estus Flask Sep 06 '18 at 16:30
  • @estus I stand corrected on this. You're correct given the context, my apologies. If you edit this answer (add a space or something) I'll upvote this since its both educational and valid. – dysfunc Sep 06 '18 at 16:59
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179567/discussion-between-dysfunc-and-estus). – dysfunc Sep 06 '18 at 17:09
0

It's hard to get any value from unit tests for private methods.

Why do you may want that?

  1. To increase test coverage KPI. But once private methods are called by public - they will be taken into account anyway.
  2. To ensure everything is working... But making tests for private methods may lead to:

    a. tests are broken while component as a part of system works fine(say, private method has been changed, renamed or removed... but not tests for it) - false negative

    b. tests for private methods are fine, but component is broken(say, private method is needed to be called but it is not) - false positive

skyboyer
  • 22,209
  • 7
  • 57
  • 64
  • This is really helpful. Thanks for clarifying! – Jalal Sep 06 '18 at 14:33
  • As for a, it's perfectly ok, failed test is a thing you expect when you do significant changes to the code. As for b, this is solved by spying on a function, this isn't possible if a function resides in same module and isn't a method. – Estus Flask Sep 06 '18 at 15:11
  • I don't agree with this. There is a ton of value in testing private methods directly especially if they perform transforms or contain a decent amount of logic. Why not ensure all the private method use cases & edge cases are covered? You have to write tests for the component which will cover the majority of the use cases for the private function but more often than not someone new to the codebase misuses that function and the tests don't account for that so it goes unnoticed. It's better to be thorough than to write tests with tunnel vision. – dysfunc Sep 06 '18 at 16:01
  • @dysfunc so there is a piece of complex logic. and it is not exposed. so it cannot be reused somewhere else. so it is either so unique that make sense just in single place and specific case or it is complicated not complex and should be decomposed for reusability. – skyboyer Sep 06 '18 at 16:05
  • If the function is a utility/common function it should be moved to its own module and tested independently/thoroughly but why not test everything for a given module? If the class depends on that function to do something to in order to function properly it should be tested in its entirety – dysfunc Sep 06 '18 at 16:08
  • @dysfunc because of efficiency. making test for every single method does not mean there are no error inside. but it definitely mean we need to make double work on every single change inside. even renaming. and it means either less performance or a one will avoid refactoring in any cost because it would mean rewriting tons of unit tests. – skyboyer Sep 06 '18 at 16:13
  • on contrast our unit tests for public API not only are testing for errors but also ensures we don't miss breaking change in API for some component. It's crucial since we don't test mix of components in unit tests but using mocks/stubs. So if API is changed and we have not expected that(unit tests fails for public API) it means system may break in some place where it's integrated. – skyboyer Sep 06 '18 at 16:17
  • you've officially lost me. how does performance come into play? because we are adding 20-100 lines of additional test code? I can run 10k tests using mocha in about a minute... so let's not use that as an argument. Also, if things change you need to change your tests and if things are failing your tests are doing their job. – dysfunc Sep 06 '18 at 16:20
  • I guess will have to agree to disagree – dysfunc Sep 06 '18 at 16:20
  • @dysfunc c'mon, it's not about perfomance of execution(which is also important - I saw how developers switched off git hooks because unit tests took 10 minutes to run). It's about performance of making things. Writing the tests is not a goal by itself. – skyboyer Sep 06 '18 at 16:26