#Hello I am new to unit testing and I would like to ask a few questions.

13 messages · Page 1 of 1 (latest)

frosty granite
#

Currently when writing unit tests for a service when I create the module I have to specify all of the dependencies present in the service's constructor otherwise the test suite fails. Is there a way to only import only the dependencies which are of concern during testing or is this the only way.

Also when I'm writing tests for different cases I'm creating new mocks every time because of the needs of the test case. Should I create a factory for those mocks? And if yes where is it a good place to keep them? I currently keep them in test/mocks which is on the same level as src.

Another problem I've came across is suppose I want to mock the resolved value of a function within the service I'm writing the tests for. But that function is private and I cannot access it in my test file. The way I solved it is I created a MockService class and overrode those methods as public. Is this a viable solution and are there better ways to do it?

jovial condor
#

I have to specify all of the dependencies present in the service's constructor

as far as I know you indeed have to specify all of the constructor deps. but what exactly do you mock latter in test? i mean do you use real instances of decencies classes and mock only methods or do you mock the instances themselves?

do you mock them with NestJS dependency injection?

Should I create a factory for those mocks?

based on this message i'm assuming you are mocking tho whole dep instance, right? if so there are auto-mocking techniques provided by test frameworks. for example vite allows you to mock the whole JS module meaning not related to NestJS at all. this way you can have one "default" minimal mock of each service dependency and then adjust it on a per-test level with mockImplementationOnce or whatever else

here is an example of how them mock node:fs module, but same technique can be applied to mock your source code files that are dependencies of tested service.

https://vitest.dev/guide/mocking#example-3

But that function is private

you commonly want to avoid testing/mocking private functionality, as it considered technical implementation details. i would recommend to mock external deps, that this private function uses, and test the public function, that under the hood calls for private one. so from the unit test perspective whatever amount of private function service has it is just a blackbox (except for targeted public method)

frosty granite
# jovial condor > I have to specify all of the dependencies present in the service's constructor...

Suppose I have a function for distributing rewards. It is a private method and when it's called inside of another method it doesn't really return a response. Inside it's body it does several calculations to assure that the rewards are distributed correctly. We have to ensure that the rewards are calculated correctly. The function for calculation is also private. So I don't really have any access to it at all if I don't create a mock of the service and expose said methods.

#

The response returned from the calculation function is assigned to a variable and then another private method is called to hand out each reward to each participant individually as we loop through the winners.

jovial condor
# frosty granite The response returned from the calculation function is assigned to a variable an...

ok, i see where it goes. i usually prefer to write pure functions whenever possible so the case your are describing is somewhat rare to me

lets put aside pure vs side-effect function debate, because its a different topic and can potentially lead to a lot of refactor effort

is this variable, that gets a value assigned, public? if yes, I would swap it with a pair of getter and setter to spy on and mock this variable

frosty granite
frosty granite
#

The only solution I came up with (that looks somewhat clean) is making the methods protected and extending the service from a MockService class that overwrites those methods as public and calls their implementation. I keep it in test/mocks. The test folder is the one that's on the same level as src. It's where I plan on eventually keeping all of my mock classes for services and mock factories.

#

Also just a side question but I have to mock the return value of a createQueryBuilder that chains down to getCount. Problem is I also have to mock all of the other chained methods. Currently I've done this:

  const mockQueryBuiler = {
    createQueryBuilder: jest.fn().mockReturnValue({
      select: jest.fn().mockReturnThis(),
      where: jest.fn().mockReturnThis(),
      groupBy: jest.fn().mockReturnThis(),
      getCount: jest.fn(),
      limit: jest.fn().mockReturnThis(),
      leftJoinAndSelect: jest.fn().mockReturnThis(),
      leftJoin: jest.fn().mockReturnThis(),
      addSelect: jest.fn().mockReturnThis(),
      getMany: jest.fn(),
    }),
  };
#

I am only tasked with writing the tests and can't do much about the code. If it were up to me I would separate the whole call into a separate function to get the player count and just mock that function instead of dealing with the query builder...

jovial condor
# frosty granite The variable itself is function scoped. It cannot be accessed out of the functio...

very interesting case indeed😅

first of all in worst case scenario since private is only a TS construct you can simply @ts-ignore whatever you need in tests and test private methods. for me it sounds cleaner than making pritected something that is meant to be private

so do I understand correctly that your flow goes something like this?

  • you have public functionA and private functionB with functionC
  • internally functionA creates some function-scoped variable and passes it to functionB
  • functionB modifies this variable but has no return value
  • then functionA passes this modified variable to functionC
  • functionC performs some actions based on this variable value and also has no return value

if this is the case does actions performed by functionC involve some other services, that you can mock and validate that functionC passed there expected arguments?

frosty granite
#

It's as follows:

  • I have a public functionA that calls a private functionB (in my case it's called distributeRewards) without assigning the result to anything.

  • Inside of the private functionB, another private functionC (in my case calulateRewards) is called and assigned to a varaiable.

  • Inside of the same functionB the result (returned from calculateRewards) is looped through and for each of the objects another private functionD (in my case handOutRewards) is called to handout out the reward for each participant individually.

frosty granite
#

Also I have no past experience with unit testing. Im writing a test for a code that's already there meaning I have to understand how it works in order to test it... This is how my test looks like for testing whether the rewards are calculated correctly. (Just to clarify I can access calculateRewards because I have created a MockService and extended).

    it("should handle case with all players tied", () => {
      const mockPlayers: Winner[] = [
        { player_id: 1, game_ids: [1], total_points: 100 },
        { player_id: 2, game_ids: [1], total_points: 100 },
        { player_id: 3, game_ids: [1], total_points: 100 },
        { player_id: 4, game_ids: [1], total_points: 100 },
      ];

      const result: RewardedWinner[] = tournamentService.calculateWinnings(
        mockTournament,
        mockPlayers
      );

      expect(result).toEqual([
        { player_id: 1, game_ids: [1], total_points: 100, reward: 250, percentage: 0.25 },
        { player_id: 2, game_ids: [1], total_points: 100, reward: 250, percentage: 0.25 },
        { player_id: 3, game_ids: [1], total_points: 100, reward: 250, percentage: 0.25 },
        { player_id: 4, game_ids: [1], total_points: 100, reward: 250, percentage: 0.25 },
      ]);
    });