簡體   English   中英

fp-ts 和jest:Option 和Either 的人體工程學測試?

[英]fp-ts and jest: ergonomic tests for Option and Either?

我正在使用fp-ts ,並使用 Jest 編寫單元測試。 在許多情況下,我正在測試可為空的結果,通常用OptionEither表示(通常,數組find s)。 如果結果是無(以Option為例),並且繼續知道這個結果是一些,那么使測試失敗的最符合人體工程學的方法是什么?

這是我目前如何解決問題的示例:

function someFunc(input: string): Option.Option<string> {
  return Option.some(input);
}

describe(`Some suite`, () => {
  it(`should do something with a "some" result`, () => {
    const result = someFunc('abcd');

    // This is a fail case, here I'm expecting result to be Some
    if(Option.isNone(result)) {
      expect(Option.isSome(result)).toEqual(true);
      return;
    }

    expect(result.value).toEqual('abcd');
  });
});

但是必須寫一個提前返回的 if 不是很符合人體工程學。

我也可以寫一個as斷言:

  // ...
  it(`should do something with a "some" result`, () => {
    const result = someFunc('abcd') as Option.Some<string>;

    expect(result.value).toEqual('abcd');
  });
  // ...

但缺點是我必須重寫some的類型。 在許多情況下,必須編寫它是繁重的,需要編寫和導出接口僅用於測試目的(這也不符合人體工程學)。

有沒有辦法簡化這種測試?

編輯:這是一個更接近真實條件的測試用例:


interface SomeComplexType {
  id: string,
  inputAsArray: string[],
  input: string;
}

function someFunc(input: string): Option.Option<SomeComplexType> {
  return Option.some({
    id: '5',
    inputAsArray: input.split(''),
    input,
  });
}

describe(`Some suite`, () => {
  it(`should do something with a "some" result`, () => {
    const result = someFunc('abcd');

    // This is the un-ergonomic step
    if(Option.isNone(result)) {
      expect(Option.isSome(result)).toEqual(true);
      return;
    }

    // Ideally, I would only need this:
    expect(Option.isSome(result)).toEqual(true);
    // Since nothing will be ran after it if the result is not "some"
    // But I can imagine it's unlikely that TS could figure that out from Jest expects

    // Since I now have the value's actual type, I can do a lot with it
    // I don't have to check it for nullability, and I don't have to write its type
    const myValue = result.value;

    expect(myValue.inputAsArray).toEqual(expect.arrayContaining(['a', 'b', 'c', 'd']));

    const someOtherThing = getTheOtherThing(myValue.id);

    expect(someOtherThing).toMatchObject({
      another: 'thing',
    });
  });
});

toNullabletoUndefined怎么toUndefined 給定Option<string>toNullable返回string | null string | null

import { toNullable, toUndefined } from "fp-ts/lib/Option";

it(`should do something with a "some" result`, () => {
  expect(toNullable(someFunc("abcd"))).toEqual("abcd");
});

expect(Option.isSome(result)).toEqual(true)是,類型保護isSome不能用於縮小expect外部代碼路徑中的result (請參閱此處控制流分析的工作原理)。

您可以使用更精簡的斷言函數並將它們與fp-ts類型保護相結合,例如:

import { isSome, Option } from "fp-ts/lib/Option"

function assert<T>(guard: (o: any) => o is T, o: any): asserts o is T {
  if (!guard(o)) throw new Error() // or add param for custom error
}

it(`a test`, () => {
  const result: Option<string> = {...}
  assert(isSome, result)
  // result is narrowed to type "Some" here
  expect(result.value).toEqual('abcd');
});

我不知道是否有一種用類型保護簽名來增強 Jest expect函數類型本身的好方法,但我懷疑它是否簡化了您的案例,而不是簡單的斷言或以上解決方案。

你可以像這樣從fromSome寫一個不安全的轉換:

function fromSome<T>(input: Option.Option<T>): T {
  if (Option.isNone(input)) {
    throw new Error();
  }
  return input.value;
}

然后在測試中使用它

  it(`should do something with a "some" result`, () => {
    const result = someFunc('abcd');
    const myValue = fromSome(result);
    // do something with myValue
  });

這個問題是在這一點上有點歷史,擁有一個公認的答案,但也有使測試夫婦非常好的圖書館fp-ts EitherOption真正愉快。 他們都工作得很好,我真的無法決定我更喜歡哪個。

它們允許你寫這樣的東西:

test('some test', () => {
  expect(E.left({ code: 'invalid' })).toSubsetEqualLeft({ code: 'invalid' })
})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM