错误:<spyOn>:fromEvent未声明为可写或没有setter

时间:2019-07-26 06:24:49

标签: angular

我用的是这个

import * as ObservableEvents from 'rxjs/Observable/fromEvent';
spyOn(ObservableEvents, 'fromEvent').and.returnValue(new Subject<any>().asObservable());

我得到的错误:

  

错误:: fromEvent未声明为可写或没有设置器

4 个答案:

答案 0 :(得分:1)

您需要监视rxjs的属性。使用spyOnProperty将解决该错误。试试这个

res = ([], [])

for s in strings:
    res["update" in s].append(s)

no_update, with_update = res

您也可以使用类似的方法将其添加到getter / setter中

>>> print(with_update)
['Beta_Gambus_teta_wqtr_update_2017.02.1277.ctr', 'Beta_Gambus_teta_tpesdr_update_2017.02.1277.ctr', 'Beta_Gambus_teta_cnms_update_2018.02.1279.ctr']
>>> print(no_update)
['Beta_Gambus_teta_wqtr_2017.02.1276.ctr', 'Beta_Gambus_teta_tpsedr_2017.02.1276.ctr', 'Beta_Gambus_teta_cnmsr_2018.02.1279.ctr']

希望这会有所帮助

答案 1 :(得分:1)

您不能监视模块导入,因为它是只读的。 Here's和GitHub中的Jasmine issue都是相同的rxjs问题。

但是,您真的要监视fromEvent函数吗?如果您要检查类/函数是否调用fromEvent,则不要这样做。测试应测试API,但不测试实现。很难维护这样的测试,即测试实现。您应该测试黑匣子,而不应该考虑它们的实现方式。

如果您要在测试内部使用fromEvent,则测试其行为就不是问题。如果无论如何对您来说很重要,要测试事件如何转换为可观察对象,您可以创建一个“ fromEvent”包装器并对其进行模拟,例如:

class EventTransformer {
  transform<T>(target: FromEventTarget<T>, eventName: string): Observable<T> {
    return fromEvent(target, eventName);
  }
}

class MyClass {
  constructor(private eventTransformer: EventTransformer) {}
  doSomething() { /* transform some event */ }
}

it('test', () => {
  const eventTransformer = jasmine.createSpyObj<EventTransformer>(EventTransformer.name, [
    'transform',
  ]);
  eventTransformer.transform.and.returnValue(of({}));

  const myClass = new MyClass(eventTransformer)
  myClass.doSomething();
});

Another workaround,是通过更新测试tsconfig来使用“ commonjs”模块。

"compilerOptions": {
    ....
    // force commonjs module output, since it let mock exported members on modules to anywhere in the application (even in the same file)
    "module": "commonjs",
},

答案 2 :(得分:0)

补充Omair的答案。就我而言,我需要在returnValue语句上有一个函数。

const fromEventSpy = spyOnProperty(rxjs, 'fromEvent').and.returnValue(() => rxjs.of({}));

干杯!

答案 3 :(得分:0)

允许监视模块的 Angular +10 解决方案“import * as XXX from 'abc'

添加到 tsconfig.spec.json

"compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        ...
    },

props moduletarget 都很重要!除非目标设置为 es5 并且模块不是 commonjs,否则这将不起作用;

现在在您的规范文件中,您可以执行以下操作:

    import * as selectors from '@app/state';
    
    const mockModuleFunc = (importModule: any, methodName: string, returnValue: any = null) => {
       let currentVal = importModule[methodName];
       const descriptor = Object.getOwnPropertyDescriptor(importModule, methodName);
       if(!descriptor.set) {
          Object.defineProperty(importModule, methodName, {
             set(newVal) {
                    currentVal = newVal;
                },
                get() {
                    return currentVal;
                },
                enumerable: true,
                configurable: true
          });
       }
    
       /** 
        * This actually works now and doesn't throw "is not declared writable or has no setter" error.
        * Use spyOn as always, example with parameterized ngrx selectors:
        */
       return spyOn(importModule, methodName).and.returnValue(() => returnValue);
    }

// Usage example
it('Your test description', () => {
       const spy = mockModuleFunc(selectors, 'yourFunctionToSpyOn', 'xyz');
    
       ...
    })