【问题标题】:How to Implement a general Save() Function in a Base Class如何在基类中实现通用 Save() 函数
【发布时间】:2021-07-25 20:21:43
【问题描述】:

作为评估,我收到了以下测试用例,因此我可以实现背后的代码:

[TestCase]
public void ProgrammerTest() 
{
    var address = new Address("56 Main St", "Mesa", "AZ", "38574");
    var customer = new Customer("John", "Doe", address);
    var company = new Company("Google", address);
 
    Assert.IsNullOrEmpty(customer.Id);
    customer.Save();
    Assert.IsNotNullOrEmpty(customer.Id);
 
    Assert.IsNullOrEmpty(company.Id);
    company.Save();
    Assert.IsNotNullOrEmpty(company.Id);
 
    Customer savedCustomer = Customer.Find(customer.Id);
    Assert.IsNotNull(savedCustomer);
    Assert.AreSame(customer.Address, address);
    Assert.AreEqual(savedCustomer.Address, address);
    Assert.AreEqual(customer.Id, savedCustomer.Id);
    Assert.AreEqual(customer.FirstName, savedCustomer.FirstName);
    Assert.AreEqual(customer.LastName, savedCustomer.LastName);
    Assert.AreEqual(customer, savedCustomer);
    Assert.AreNotSame(customer, savedCustomer);
 
    Company savedCompany = Company.Find(company.Id);
    Assert.IsNotNull(savedCompany);
    Assert.AreSame(company.Address, address);
    Assert.AreEqual(savedCompany.Address, address);
    Assert.AreEqual(company.Id, savedCompany.Id);
    Assert.AreEqual(company.Name, savedCompany.Name);
    Assert.AreEqual(company, savedCompany);
    Assert.AreNotSame(company, savedCompany);
 
    customer.Delete();
    Assert.IsNullOrEmpty(customer.Id);
    Assert.IsNull(Customer.Find(customer.Id));
 
    company.Delete();
    Assert.IsNullOrEmpty(company.Id);
    Assert.IsNull(Company.Find(company.Id));
}

要求是:

  • 在 C# 中创建一个单独的类,当子类化时允许此示例测试代码运行仅使用文件系统进行存储,不允许预建数据库;使用文件。
  • 创建编译和通过测试用例所需的所有类;你不能修改测试。测试没有错,不是骗人的。
  • IdSaveDeleteFind 方法只能在超类中;子类不得自行实现这些方法。

这是我可以从测试用例中提取的一个类示例:

public abstract class MyBase
{
    public abstract void Save();
    public abstract void Delete();
}

public class Company : MyBase
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }

    public Company(string name, Address address)
    {
        this.Name = name;
        this.Address = address;
    }

    internal static Company Find(string id)
    {
        throw new NotImplementedException();
    }

    public override void Delete()
    {
       throw new NotImplementedException();
    }

    public override void Save()
    {
        object company = new List<Company>();

        if (company != null)
        {
            // serialize JSON to a string and then write string to a file
            File.WriteAllText(@"c:\company.json", JsonConvert.SerializeObject(company));
        }
    }
}

我有为给定代码创建 TestCases 的经验,但不是其他方式,我可以从中提取类,但是,我如何将方法 Save()Delete()Find(customer.Id) 实现为没有的通用类型传递填充的数据类?我知道我可以做类似void Save(object obj) 的事情并在Base 上实现传递的对象,但是测试用例只是像customer.Save() 这样调用......那么,我该怎么做呢?

提前感谢您的任何意见!

【问题讨论】:

    标签: c# class testcase


    【解决方案1】:

    我假设其意图是使用某种序列化来生成对象的副本。

    Json

    如果使用 json.net,您应该能够使用名称处理将实际对象类型包含在序列化消息中:

    JsonSerializerSettings settings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All
    };
    
    string strJson = JsonConvert.SerializeObject(instance, settings);
    

    来自how to deserialize JSON into IEnumerable with Newtonsoft JSON.NET

    Protobuf

    您还可以将protobuf.net 与 ProtoInclude 一起使用,以允许它序列化子类型:

    [ProtoContract]
    [ProtoInclude(7, typeof(SomeDerivedType))]
    class SomeBaseType {...}
    
    [ProtoContract]
    class SomeDerivedType {...}
    

    然后基本类型应该能够将this序列化为内存流并再次反序列化,将副本存储在静态列表中,然后让 find 方法搜索列表。

    受保护的虚拟/抽象成员

    另一种方法是将protected virtual 方法添加到子类型以完成创建相同对象的所有实际工作。该任务仅指定Save 方法需要在基类型上,而不是它需要在没有子类型帮助的情况下完成实际工作。

    请注意,由于几个问题,我不会推荐该作业中的做法:

    • 通过测试的最简单方法是使用静态可变字段,通常不建议使用这些字段。
    • 在某些情况下,使用序列化生成深层副本可能是合适的,但我通常建议不要这样做。原因是并非所有类型都应该是可序列化的,而且深拷贝的构建可能相当便宜。
    • 说明建议写入文件。单元测试通常应避免写入磁盘,因为磁盘相对较慢,并且单元测试需要快速运行才能发挥作用。
    • 我发现需要副本的情况很少见。在许多情况下,不可变对象更易于使用,并且不需要复制。
    • 整个测试看起来相当荒谬。如果我在野外看到它会触发相当多的 WTF。

    【讨论】:

      猜你喜欢
      • 2021-05-24
      • 1970-01-01
      • 2021-06-25
      • 2019-07-16
      • 1970-01-01
      • 2017-01-20
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      相关资源
      最近更新 更多