Учитывая следующий класс:
import { BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
export class ObjectStateContainer<T> {
private currentStateSubject = new BehaviorSubject<T>(undefined);
private $currentState = this.currentStateSubject.asObservable();
public $isDirty = this.$currentState.pipe(map(t => t !== this.t));
constructor(public t: T) {
this.update(t);
}
undoChanges() {
this.currentStateSubject.next(this.t);
}
update(t: T) {
this.currentStateSubject.next(t);
}
}
Я хотел бы написать несколько тестов, подтверждающих, что $isDirty
содержит значение, которое я ожидал бы после выполнения различных вызовов функций. В частности, я хотел бы протестировать создание переменной, ее обновление, а затем отмену изменений и проверку значения $isDirty
для каждого этапа. В настоящее время я видел два способа тестирования наблюдаемых и не могу понять, как провести этот тест с любым из них. Я бы хотел, чтобы тест проделал следующее:
- Create a new
ObjectStateContainer
.- Assert that
$isDirty
is false.
- Assert that
- Invoke update on the
ObjectStateContainer
.- Assert that
$isDirty
is true.
- Assert that
- Invoke undoChanges on the
ObjectStateContainer
.- Assert that
$isDirty
is false.
- Assert that
import { ObjectStateContainer } from './object-state-container';
import { TestScheduler } from 'rxjs/testing';
class TestObject {
}
describe('ObjectStateContainer', () => {
let scheduler: TestScheduler;
beforeEach(() =>
scheduler = new TestScheduler((actual, expected) =>
{
expect(actual).toEqual(expected);
})
);
/*
SAME TEST AS ONE BELOW
This is a non-marble test example.
*/
it('should be constructed with isDirty as false', done => {
const objectStateContainer = new ObjectStateContainer(new TestObject());
objectStateContainer.update(new TestObject());
objectStateContainer.undoChanges();
/*
- If done isn't called then the test method will finish immediately without waiting for the asserts inside the subscribe.
- Using done though, it gets called after the first value in the stream and doesn't wait for the other two values to be emitted.
- Also, since the subscribe is being done here after update and undoChanges, the two previous values will already be gone from the stream. The BehaviorSubject backing the observable will retain the last value emitted to the stream which would be false here.
I can't figure out how to test the whole chain of emitted values.
*/
objectStateContainer
.$isDirty
.subscribe(isDirty => {
expect(isDirty).toBe(false);
expect(isDirty).toBe(true);
expect(isDirty).toBe(false);
done();
});
});
/*
SAME TEST AS ONE ABOVE
This is a 'marble' test example.
*/
it('should be constructed with isDirty as false', () => {
scheduler.run(({ expectObservable }) => {
const objectStateContainer = new ObjectStateContainer(new TestObject());
objectStateContainer.update(new TestObject());
objectStateContainer.undoChanges();
/*
- This will fail with some error message about expected length was 3 but got a length of one. This seemingly is happening because the only value emitted after the 'subscribe' being performed by the framework is the one that gets replayed from the BehaviorSubject which would be the one from undoChanges. The other two have already been discarded.
- Since the subscribe is being done here after update and undoChanges, the two previous values will already be gone from the stream. The BehaviorSubject backing the observable will retain the last value emitted to the stream which would be false here.
I can't figure out how to test the whole chain of emitted values.
*/
const expectedMarble = 'abc';
const expectedIsDirty = { a: false, b: true, c: false };
expectObservable(objectStateContainer.$isDirty).toBe(expectedMarble, expectedIsDirty);
});
});
});
t => t !== t
не всегда будет возвращать false? Вы имели в видуt => t !== this.t
? - person Andrei Gătej   schedule 11.05.2020