2

私は WebApi2 を使用してプロジェクトに取り組んでいます。私のテスト プロジェクトでは、Moq と XUnit を使用しています。

これまでのところ、API のテストは、GET のようなものを実行するのは非常に簡単でした。

  [Fact()]
    public void GetCustomer()
    {
        var id = 2;

        _customerMock.Setup(c => c.FindSingle(id))
            .Returns(FakeCustomers()
            .Single(cust => cust.Id == id));

        var result = new CustomersController(_customerMock.Object).Get(id);

        var negotiatedResult = result as OkContentActionResult<Customer>;
        Assert.NotNull(negotiatedResult);
        Assert.IsType<OkNegotiatedContentResult<Customer>>(negotiatedResult);
        Assert.Equal(negotiatedResult.Content.Id,id);
    }

ここで、リクエスト ヘッダーから値にアクセスする必要がある、少し複雑な作業に移ります。

IHttpActionResult を拡張して、独自の Ok() 結果を作成しました

   public OkContentActionResult(T content,HttpRequestMessage request)
    {
        _request = request;
        _content = content;
    }

これにより、リクエストからヘッダー値を読み取る小さなヘルパーを作成できます。

 public virtual IHttpActionResult Post(Customer customer)
    {
        var header = RequestHeader.GetHeaderValue("customerId", this.Request);

        if (header != "1234")

ダミーのリクエストでMoqをセットアップするにはどうすればよいですか?

過去 1 時間ほどかけて、webapi でこれを実行できる例を探しましたが、何も見つからないようです。

これまでのところ...そして、APIにとっては間違っていると確信していますが、私は持っています

      // arrange
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var headers = new NameValueCollection
        {
            { "customerId", "111111" }
        };
        request.Setup(x => x.Headers).Returns(headers);
        request.Setup(x => x.HttpMethod).Returns("GET");
        request.Setup(x => x.Url).Returns(new Uri("http://foo.com"));
        request.Setup(x => x.RawUrl).Returns("/foo");
        context.Setup(x => x.Request).Returns(request.Object);
        var controller = new Mock<ControllerBase>();
        _customerController = new CustomerController()
        {
            //  Request = request,

        };

過去にモック HttpRequestBase をセットアップする必要がなかったため、次に何をする必要があるかはよくわかりません。

誰かが良い記事を提案したり、私を正しい方向に向けたりできますか?

ありがとうございました!!!

4

1 に答える 1

7

問題をより適切に分離するために、コントローラーのヘッダーを読み取らないようにする必要があると思います (コントローラーの要求本文から Customer を読み取る必要はありませんよね?)。

私がそれを行う方法は、CustomerIdクラスを作成することです(これはオプションです。以下の注を参照してください)CustomerIdParameterBinding

public class CustomerId
{
    public string Value { get; set; }
}

public class CustomerIdParameterBinding : HttpParameterBinding
{
    public CustomerIdParameterBinding(HttpParameterDescriptor parameter) 
    : base(parameter)
    {
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        actionContext.ActionArguments[Descriptor.ParameterName] = new CustomerId { Value = GetIdOrNull(actionContext) };
        return Task.FromResult(0);
    }

    private string GetIdOrNull(HttpActionContext actionContext)
    {
        IEnumerable<string> idValues;
        if(actionContext.Request.Headers.TryGetValues("customerId", out idValues))
        {
            return idValues.First();
        }
        return null;
    }
}

CustomerIdParameterBinding を作成する

config.ParameterBindingRules.Add(p =>
{
    return p.ParameterType == typeof(CustomerId) ? new CustomerIdParameterBinding(p) : null;
});

次に、私のコントローラーで

public void Post(CustomerId id, Customer customer)

パラメータバインディングのテスト

public void TestMethod()
{
    var parameterName = "TestParam";
    var expectedCustomerIdValue = "Yehey!";

    //Arrange
    var requestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri");
    requestMessage.Headers.Add("customerId", expectedCustomerIdValue );

    var httpActionContext = new HttpActionContext
    {
        ControllerContext = new HttpControllerContext
        {
            Request = requestMessage
        }
    };

    var stubParameterDescriptor = new Mock<HttpParameterDescriptor>();
    stubParameterDescriptor.SetupGet(i => i.ParameterName).Returns(parameterName);

    //Act
    var customerIdParameterBinding = new CustomerIdParameterBinding(stubParameterDescriptor.Object);
    customerIdParameterBinding.ExecuteBindingAsync(null, httpActionContext, (new CancellationTokenSource()).Token).Wait();

    //Assert here
    //httpActionContext.ActionArguments[parameterName] contains the CustomerId
}

: クラスを作成したくない場合はCustomerId、パラメータにカスタム アノテーションを付けることができますParameterBindingAttribute。そのようです

public void Post([CustomerId] string customerId, Customer customer)

ParameterBindingAttribute の作成方法については、こちらを参照してください

于 2014-01-16T04:37:08.067 に答える