F # или C # |Как проверить, что метод расширения вызывается? - PullRequest
0 голосов
/ 19 февраля 2019

Когда у меня есть тип MyType и этот код:

// models.fs

type internal Ticker(price:decimal, time:System.DateTime) =
    member this.Price = price
    member this.Time = time

// cache.fs

module internal cache

type TickerCache = {date:DateTime; ticker:Ticker}

let cache_duration = TimeSpan.FromSeconds 60.0
let cache_tickers = Dictionary<string, TickerCache>()

let isCached currency_pair = 
    cache_tickers.ContainsKey currency_pair && (DateTime.UtcNow - cache_tickers.Item(currency_pair).date) < cache_duration


let getTicker currency_pair = 
    let found, item = cache_tickers.TryGetValue currency_pair        
    if found && (DateTime.UtcNow - item.date) < cache_duration then Some item.ticker
    else None

// Client.fs

namespace main

open Flurl.Http

type MyType =       

    let getTicker main, base_ = 

        let pair = sprintf"%s%s" main base_
        let cached_ticker = cache.getTicker(pair)
        if cached_ticker.IsSome then Task.FromResult(cached_ticker.Value)
        else         
            let url = sprintf"%s/ticker/%s" apiBaseUrl pair
            url.GetJsonAsync<Ticker>()

как я могу проверить, что GetJsonAsync вызывается (или нет, в зависимости от результатаиз cache.getTicker )?
Я обычно использую Moq, чтобы проверить, что вызывается определенная Setup , но в этом случае Setup использует метод расширенияСтрока вместо интерфейса, который я могу издеваться.

Предложения о том, как это протестировать?

(решение даже для C # нормально, я постараюсь перейти на F # или написать тест на C #)

[edit] Почему MyType является типом?
Этот код предназначен для генерации клиента, который будет использоваться проектом C # следующим образом:
(MyType Client )

var configuration = new Configuration(tickerCacheTTL, publicKey, secretKey);
IClient client = new Client(configuration);
var ticker = client.getTicker("A", "B");

type генерирует class , и это более ".Net friendly".Кроме того, я не хочу каждый раз передавать конфигурацию в функцию getTicker.
В реальном коде F # я использую: interface IClient with для предоставления открытых методов.

[edit 2]
Я могу использовать InternalsVisibleToAttribute в моделях.fs (Ticker, TickerCache) и cache.fs:

[<assembly:System.Runtime.CompilerServices.InternalsVisibleTo("MyProject.UnitTests")>]
do()

(и изменить тип TickerCache из частногок внутренним также), но я все еще не могу смоделировать cache.getTicker без надлежащей инъекции в клиент (MyType).

1 Ответ

0 голосов
/ 19 февраля 2019

Вы можете вставить функцию в тип, которая позволит вам проверить, закрыв изменяемое значение, которое вы можете проверить.Это потребовало бы минимальных изменений в том, что вы должны сделать, чтобы это можно было проверить.

Я собрал пример в файле сценария fsx, который, я надеюсь, демонстрирует это.

#r "packages/System.Net.Http/lib/net46/System.Net.Http.dll"
#r "packages/Flurl/lib/net40/Flurl.dll"
#r "packages/Flurl.Http/lib/net46/Flurl.Http.dll"

open System
open System.Net.Http
open Flurl
open Flurl.Http
open System.Threading.Tasks

type Ticker = {
    At: DateTime
    Value: float
}

module Ticker =

    type Data(f:string->Task<Ticker>) =

        let getTicker (m, b) =
            let url = sprintf "%s/ticker" b
            f(url)

        member this.GetTicker = getTicker


// in test
let mutable isCalled = false
let spy s = 
    isCalled <- true
    Task.FromResult({ At = DateTime.UtcNow; Value = 1.0 })

let t = Ticker.Data(spy)

let testR = t.GetTicker("whatever", "http://localhost:5000/")

// prod code
let fetchTicker (url:string) = url.GetJsonAsync<Ticker>()

let p = Ticker.Data(fetchTicker)

let result = t.GetTicker("whatever", "https://some.url/")

Могут быть и другие варианты использования расширений типов (https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/type-extensions)

ItВозможно, стоит сделать шаг назад и подумать, можете ли вы подойти с другой стороны. Возможно, вы подходите так же, как и в C #, когда F # может предоставить более простой и функциональный подход. В частности, здесь я не могу точно сказать, почему вырешил использовать myType.

См. здесь некоторые идеи: https://en.wikibooks.org/wiki/F_Sharp_Programming/Caching

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...