【问题标题】:How to moq responses from Amazon MWS for unit testing如何从亚马逊 MWS 获取最小起订量响应以进行单元测试
【发布时间】:2017-04-28 00:24:04
【问题描述】:

上下文

我正在对调用亚马逊 MWS API 中的ListMatchingProducts 操作的 C# .Net 类进行单元测试(使用 MWSClientCsRuntime)。

问题

亚马逊 MWS API 是一个移动目标,产品数据一直在变化,因此我希望能够最小化 API 返回的 ListMatchingProductsResponse 对象。我可以使用 MWS 暂存器获取 API 响应并将它们存储在 xml 文件中。但是,在单元测试中,我需要将这些文件中的数据强制转换为 ListMatchingProductsResponse 对象。

问题

如何将此 xml 数据加载到 ListMatchingProductsResponse 对象中? (我注意到该对象有一个ReadFragmentsFrom 方法,但我看不出它是如何使用的)。

代码

[TestClass]
public class PossibleAmazonProductMatchesTests
{
    string testDataDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName + @"\Test data";

    [TestMethod]
    public void FindSpanners()
    {
        // Arrange

        ListMatchingProductsRequest request = new ListMatchingProductsRequest("secret key", "market id", "spanner");
        ListMatchingProductsResult result = new ListMatchingProductsResult();

        ListMatchingProductsResponse response = new ListMatchingProductsResponse();

        string xmlString = File.ReadAllText(this.testDataDirectory + @"\Spanners Response.xml");

        // *** The issue - How do I coerce xmlString into response? ***

        var client = new Mock<MarketplaceWebServiceProductsClient>();
        client.Setup(c => c.ListMatchingProducts(request)).Returns(response);

        // Act

        // This is the method being tested. It calls ListMatchingProducts which is being mocked.
        PossibleAmazonProductMatches possibleAmazonProductMatches = new PossibleAmazonProductMatches("spanners", client);

        // Assert

        Assert.IsTrue(possibleAmazonProductMatches.SpannersFound == true);
    }
}

【问题讨论】:

  • 提供一个minimal reproducible example(代码)来演示场景并更好地解释您的问题。
  • @Nkosi 全部完成。
  • 这看起来像是一个简单的例子,必须读取 XML 文件,将其从 XML 反序列化为所需的对象类型。只是想确保我明白你想要做什么。
  • 啊,这很有道理。因此,最好放弃我目前使用 MWS 暂存器获取 xml 并将其粘贴到文件中的策略。最好编写从 API 读取的内容并将其序列化到文件中。然后我可以在测试时反序列化它。如果您愿意在下面发布一些内容,很高兴将其标记为答案。
  • @ScottG 非常感谢。在客户端库中钻研,我发现 MarketplaceWebServiceProductsMock.cs 给了我一个完整的例子。再加上 Nkosi 的评论,看起来我可以在这里得到一个有用的抽象。一旦我有了它,我会发布一些工作代码。

标签: c# xml unit-testing moq amazon-mws


【解决方案1】:

这看起来很简单,必须读取 XML 文件,然后将其从 XML 反序列化为所需的对象类型。

更好的是,您可以将其抽象为执行所需行为的服务,而无需将代码与实现问题紧密耦合。

将 MWS 视为第 3 部分服务,并将其包装在您可以完全控制的抽象后面。这样您就可以在测试时配置所需的行为。

【讨论】:

  • 谢谢。整理完之后会更新我的代码示例。
【解决方案2】:

基于来自@Nkosi 和@ScottG 的热烈响应,我现在有了一个可行的解决方案,结果证明它非常简单,尽管有一些要点需要注意。所以单元测试代码如下:

[TestClass]
public class PossibleAmazonProductMatchesTests
{
    [TestMethod]
    public void Test1()
    {
        // Arrange

        var moqClient = new MarketplaceWebServiceProductsMock();

        // Act

        PossibleAmazonProductMatches possibleAmazonProductMatches = new PossibleAmazonProductMatches("spanners", moqClient);

        // Assert

        Assert.IsTrue(possibleAmazonProductMatches.PossibleProductList.Count == 10);
    }
}

..就是这样。能不能再简单点!

为了抽象,被测对象 (PossibleAmazonProductMatches) 有这个构造函数:

public PossibleAmazonProductMatches(string searchTerm, MarketplaceWebServiceProducts.MarketplaceWebServiceProducts client)
{
    // Some processing
}

需要注意的重点是:

  • MarketplaceWebServiceProducts 实际上是一个接口,尽管它不遵循 ISomething 命名约定。
  • MarketplaceWebServiceProducts 也用作 命名空间名称,因此在 PossibleAmazonProductMatches 构造函数中需要加倍的 MarketplaceWebServiceProducts.MarketplaceWebServiceProducts 语法。
  • MarketplaceWebServiceProductsMock 包含在 MWS 包中,因此无需编码。
  • 默认情况下,MarketplaceWebServiceProductsMock 从程序集中的固定 xml 模板文件中读取,并使用它来构建您的测试响应。您可以根据需要编辑此文件。我实际上想从 MWS 暂存器中创建自己的 xml 文件,并希望将它们存储在更方便的位置。我以为我可以从 MarketplaceWebServiceProductsMock 继承并覆盖相关代码来执行此操作,但事实证明这被隐藏在私有方法中。因此,我只是简单地复制了 MarketplaceWebServiceProductsMock 并对其进行了更改以满足我的需要。因此我的模拟现在看起来像这样:

    using MarketplaceWebServiceProducts.Model;
    using System;
    using System.IO;
    using MWSClientCsRuntime;
    
    namespace AmazonMWS.Tests
    {
    public class MyMWSMock : MarketplaceWebServiceProducts.MarketplaceWebServiceProducts
    {
    
        // Definitions of most methods removed for brevity. They all match the pattern of ListMatchingProductsResponse.
    
        public ListMatchingProductsResponse ListMatchingProducts(ListMatchingProductsRequest request)
        {
            return newResponse<ListMatchingProductsResponse>();
        }
    
        private T newResponse<T>() where T : IMWSResponse
        {
            FileStream xmlIn = File.Open("D:\\MyTestDataFolder\\Test1.xml", FileMode.Open);
            try
            {
                StreamReader xmlInReader = new StreamReader(xmlIn);
                string xmlStr = xmlInReader.ReadToEnd();
    
                MwsXmlReader reader = new MwsXmlReader(xmlStr);
                T obj = (T)Activator.CreateInstance(typeof(T));
                obj.ReadFragmentFrom(reader);
                obj.ResponseHeaderMetadata = new ResponseHeaderMetadata("mockRequestId", "A,B,C", "mockTimestamp", 0d, 0d, new DateTime());
                return obj;
            }
            catch (Exception e)
            {
                throw MwsUtil.Wrap(e);
            }
            finally
            {
                if (xmlIn != null) { xmlIn.Close(); }
            }
        }
    }
    

    }

【讨论】:

    【解决方案3】:

    C# client library 已经存在好几年了,开箱即用。您不必处理任何 XML,包括反序列化。如果您不想使用他们的代码但想看看它是如何完成的,请将其打开到 Visual Studio 并复制出您想要的部分。我已经使用了所有的 C# 库,它们都非常好。您找到您想要的操作并取消注释他们的代码并运行。我相信他们有示例 XML 数据,其中包含您将从各种操作中获得的所有响应。

    【讨论】:

    • 感谢您抽出宝贵时间回复。我也成功地使用了这些库,并且有几个项目正在运行。这里的问题是我正在尝试创建模拟 API 响应的单元测试,以便结果是可预测的。因此,我试图获取真正的 API 响应,将其存储并在测试中再次使用它。我使用 MWS 暂存器和编辑器获取并存储到 xml 文件。但是,我不知道如何将文件内容强制转换为 ListMatchProductsResponse 对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多