admin管理员组

文章数量:1403452

I have a typescript singleton class like so:

export default class MySingleton {
private constructor({
    prop1,
    prop2,
    ...
  }: MySingletonConfig) {
    
    this.prop1 = prop1 ?? 'defaultProp1';
    this.prop2 = prop2;
    this.prop3 = prop3 ?? 'defaultProp3';

    /* ... some instruction ... */

    MySingleton.instance = this;
  }

  static getInstance(params?: Configuration): MySingleton {
    if (!this.instance && !params) {
      throw MySingleton.instantiationError;
    }

    if (!this.instance) {
      new MySingleton(params);

      return this.instance;
    }

    return this.instance;
  }
}

When I want to unit test it using jest, like so:

describe('getInstance()', () => {
    test('it should return the same instance every time', () => {
      const params = {
       /* ... all the params ... */
      };

     
      const mySingleton = MySingleton.getInstance(params);

      expect(MySingleton.getInstance()).toEqual(mySingleton);
    });
    test('it should return the instance with the default value', () => {
      const params = {
       /* ... ONLY THE REQUIRED PARAMS ... */
      };
     
      const mySingleton = MySingleton.getInstance(params);

      expect(mySingleton.prop1).toEqual('defaultProp1');
      expect(mySingleton.prop3).toEqual('defaultProp3');
    });
  });

This is failing, because we share the same instance between the 2 tests (as the singleton pattern work), therefore the second instantiation is useless.

Is there a way to reset/destroy the previous instantiation in order to properly check if those default values are properly setted with the second intantiation?

I have a typescript singleton class like so:

export default class MySingleton {
private constructor({
    prop1,
    prop2,
    ...
  }: MySingletonConfig) {
    
    this.prop1 = prop1 ?? 'defaultProp1';
    this.prop2 = prop2;
    this.prop3 = prop3 ?? 'defaultProp3';

    /* ... some instruction ... */

    MySingleton.instance = this;
  }

  static getInstance(params?: Configuration): MySingleton {
    if (!this.instance && !params) {
      throw MySingleton.instantiationError;
    }

    if (!this.instance) {
      new MySingleton(params);

      return this.instance;
    }

    return this.instance;
  }
}

When I want to unit test it using jest, like so:

describe('getInstance()', () => {
    test('it should return the same instance every time', () => {
      const params = {
       /* ... all the params ... */
      };

     
      const mySingleton = MySingleton.getInstance(params);

      expect(MySingleton.getInstance()).toEqual(mySingleton);
    });
    test('it should return the instance with the default value', () => {
      const params = {
       /* ... ONLY THE REQUIRED PARAMS ... */
      };
     
      const mySingleton = MySingleton.getInstance(params);

      expect(mySingleton.prop1).toEqual('defaultProp1');
      expect(mySingleton.prop3).toEqual('defaultProp3');
    });
  });

This is failing, because we share the same instance between the 2 tests (as the singleton pattern work), therefore the second instantiation is useless.

Is there a way to reset/destroy the previous instantiation in order to properly check if those default values are properly setted with the second intantiation?

Share Improve this question edited Dec 30, 2020 at 18:45 jonrsharpe 122k30 gold badges268 silver badges476 bronze badges asked Dec 30, 2020 at 18:18 SufianeSufiane 2,2362 gold badges17 silver badges25 bronze badges 12
  • Hold on a second. What does the tests sharing the same singleton have anything to do with the singleton having or not having the default values? If you don't change their values, then they will start off with whatever their defaults are. Edit: to clarify, if your tests that checks for default values happens before any other test that modifies them, then they will have the default values. – Taplar Commented Dec 30, 2020 at 18:25
  • 1 Can you access the MySingleton.instance field from the tests? If so, you could set that to null at the start of every test. @Taplar He is trying to test the getInstance function. However if there is an instance, the behavior changes so he can't verify this properly. – marcelwgn Commented Dec 30, 2020 at 18:28
  • @chingucoding I understand that. What I'm saying is, if the value are not changed, they will be the defaults. So if the describe for the getInstance method had a beforeAll that made a call to the getInstance to create the default instance, then both the "same instance" test and the "default values" tests could both use the same thing and work. The only plication with that is if jest/jasmine is setup to run the specs in a random order. – Taplar Commented Dec 30, 2020 at 18:36
  • 1 I'm not intimately familiar with typescript. Is there a way to make the instance 'protected'? Such that, you could write a TestMySingleton class that extends the MySingleton class, that has a method that destroys the instance? – Taplar Commented Dec 30, 2020 at 18:38
  • 1 If what values are not changed? When one of the tests succeeds, the instance property of MySingleton is set, the next test will not change the instance then since you did not clear the instance. The question is about how to reset that instance, so how to implement the beforeAll – marcelwgn Commented Dec 30, 2020 at 18:39
 |  Show 7 more ments

3 Answers 3

Reset to default 2

Ideally the istance property should be really private, but nobody prevents you from adding a reset() method on your class. It is not particularly neat, as it would basically be for testing purposes only, but at least it would be more close to the canonical implementation of the singleton pattern.

That being said, I would carefully consider if using a singleton is a good idea. It might create a lot of headaches when unit testing your code. Basically, the same problem you have here could present itself elsewhere when you try to test some code that makes use of your singleton.

I don't see why you couldn't do:

MySingleton.instance = null;
const mySingleton = MySingleton.getInstance(params);
Reflect.set(FixturesManager, 'instance', undefined)

本文标签: javascriptreset typescript singleton instance in each unit testStack Overflow