【问题标题】:FakeItEasy returning the wrong returnFakeItEasy 返回错误的返回
【发布时间】:2018-12-22 20:18:56
【问题描述】:

在下面的代码中,我有“howmanystringasync”方法,它正在调用另外两个方法。这两个是假的。 由于“.ToList()”,第二个假的返回不起作用。

我通常返回 IEnumerable,因为在某些情况下我想限制调用者的操作。有时,我会直接在输入中询问一个 List,这样一个方法就可以完成 List 所提供的功能。

我怎样才能使下面的测试有效?

var 结果 = 等待 f.AccessTheWebAsync2(web.ToList());

using FakeItEasy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace api.tests.unit
{
    public class SpecialString
    {
        public int IntProperty { get; set; }
        public string StringProperty { get; set; }

        public override bool Equals(object obj)
        {

            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            if (ReferenceEquals(this, obj)) return true;

            return Equals(obj as SpecialString);
        }

        public bool Equals(SpecialString other)
        {
            if (other == null) return false;

            return (this.IntProperty == other.IntProperty) && (this.StringProperty == other.StringProperty);
        }
    }

    public interface IFoo
    {
        Task<IEnumerable<SpecialString>> AccessTheWebAsync(int a, int b);
        Task<int> AccessTheWebAsync2(List<SpecialString> integers);
    }

    public class Foo : IFoo
    {
        public async Task<IEnumerable<SpecialString>> AccessTheWebAsync(int a, int b)
        {
            HttpClient client = new HttpClient();
            string result = await client.GetStringAsync("https://msdn.microsoft.com");

            var results = new List<SpecialString> {
                        new SpecialString{
                            IntProperty = 1,
                            StringProperty = "stringprop1"
                        },
                    new SpecialString{
                        IntProperty =2,
                        StringProperty = "stringprop2"
                    }
                };

            return results;
        }

        public async Task<int> AccessTheWebAsync2(List<SpecialString> specialstrings)
        {
            HttpClient client = new HttpClient();
            string result = await client.GetStringAsync("https://msdn.microsoft.com");

            var results = new List<SpecialString> {
                        new SpecialString{
                            IntProperty = 1,
                            StringProperty = "stringprop1"
                        },
                    new SpecialString{
                        IntProperty =2,
                        StringProperty = "stringprop2"
                    }
                };

            return results.Count();
        }

    }

    public class BiggerFoo
    {
        private readonly IFoo f;

        public BiggerFoo(IFoo f)
        {
            this.f = f;
        }

        public async Task<int> howManyStringsAsync(int a, int b)
        {

            var web = await f.AccessTheWebAsync(a, b);

            var result = await f.AccessTheWebAsync2(web.ToList());
            return result;
        }
    }

    public class FooTest
    {
        [Fact]
        public void testasyncmethod()
        {
            var fakeFoo = A.Fake<IFoo>();
            IEnumerable<SpecialString> result = new List<SpecialString> {
                        new SpecialString{
                            IntProperty = 1,
                            StringProperty = "fakestringprop1"
                        },
                    new SpecialString{
                        IntProperty =2,
                        StringProperty = "fakestringprop2"
                    }
                };

            A.CallTo(() => fakeFoo.AccessTheWebAsync(1, 2)).Returns<Task<IEnumerable<SpecialString>>>(Task.FromResult(result));

            A.CallTo(() => fakeFoo.AccessTheWebAsync2(result.ToList())).Returns<Task<int>>(Task.FromResult(5));

            var bFoo = new BiggerFoo(fakeFoo);
            bFoo.howManyStringsAsync(1, 2);
        }
    }

}

【问题讨论】:

  • result.ToList()代替A&lt;IEnumerable&lt;SpecialString&gt;&gt;.Ignored不行吗?
  • 是的,但根据 API,它必须是 List,而不是 IEnumerable
  • 正如@xofz 所说,接口契约需要得到尊重。

标签: c# fakeiteasy


【解决方案1】:

如果我没看错的话,问题是您将AccessTheWebAsync2 配置为在给定特定List&lt;SpecialString&gt; 时返回5,但在您的测试中,该方法使用不同的List&lt;SpecialString&gt; 调用,并且仅List&lt;SpecialString&gt;.Equals确实引用平等,所以你得到 0 回来。如果要确保在将包含所需 SpecialStrings 的 List&lt;SpecialString&gt; 传递给 AccessTheWebAsync2 时返回 5,则需要调整约束。看起来SpecialString 也没有基于值的Equals,因此您可以考虑检查元素的属性:

A.CallTo(() => fakeFoo.AccessTheWebAsync(1, 2)).Returns(result);
A.CallTo(() => fakeFoo.AccessTheWebAsync2(
        A<List<SpecialString>>.That.Matches(l =>
            l.Count == 2 && l[0].IntProperty == 1 && l[1].StringProperty == "fakestringprop2")))
 .Returns(5);

或者,如果你真的不关心输入值,比如

A.CallTo(() => fakeFoo.AccessTheWebAsync2(A<List<SpecialString>>._))
 .Returns(5);

更新:现在您已经添加了SpecialString.Equals,使用列表的值作为调用匹配约束更容易:

A.CallTo(() => fakeFoo.AccessTheWebAsync2(
     A<List<SpecialString>>.That.IsSameSequenceAs(result)))
  .Returns(5);

如果您还没有,请查看all of the argument constraints that FakeItEasy provides

【讨论】:

  • 用 Equals 更新了代码。我觉得如果我使用 FakeItEasy 的“忽略”功能,我会错过免费测试:在给定调用者输入的情况下,使用正确的参数调用伪造方法的测试。也许我应该忽略每个伪造方法中的每个参数?
  • 很难说。我会根据具体情况进行处理。与测试的脆弱性和可读性相比,这实际上取决于每个用例以及您认为更强的断言带来什么好处。
  • 更新答案以利用您的新 Equals 方法。
猜你喜欢
  • 2015-02-11
  • 1970-01-01
  • 1970-01-01
  • 2015-06-19
  • 1970-01-01
  • 2013-02-21
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多