-1

As an assessment, I received the following Testcase so I can implement the code behind:

[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));
}

The requirements are:

  • In C# create a single class that when subclassed allows this sample test code to run using only the file system for storage, no pre-built database allowed; use files.
  • Create all classes required to compile and pass the test case; you may not modify the test. The test is not wrong, it's not a trick.
  • The Id, Save, Delete, and Find methods must be in the super class only; subclasses must not implement these methods themselves.

Here are a class example I could extract from the test cases:

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));
        }
    }
}

I have experience creating TestCases for a given code, but not the other way out and I could extract the Classes from it but, how can I implement the methods Save(), Delete(), Find(customer.Id) as Generic Types without passing the populated data classes? I know I could do something like void Save(object obj) and implement the passed object on the Base, but the testcase just calls like customer.Save()... So, how can I do this?

Thanks in advance for any input!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

1 Answers1

1

I would assume the intent is to use some kind of serialization to produce a copy of the object.

Json

If using json.net you should be able to use name-handling to include the actual object type in the serialized message:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
};

string strJson = JsonConvert.SerializeObject(instance, settings);

From how to deserialize JSON into IEnumerable with Newtonsoft JSON.NET

Protobuf

You could also use a protobuf.net with ProtoInclude to allow it to serialize subtypes:

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

[ProtoContract]
class SomeDerivedType {...}

Then the base-type should just be able to serialize this to a memory-stream and deserialize it again, store the copy in a static list, and let the find method search the list.

Protected virtual/abstract members

Another approach would be to just add protected virtual methods to the sub-types to do all the actual work of creating an identical object. The task only specified that the Save method needs to be on the base type, not that it needs to do the actual work without help from the sub-type.

Note that I would not recommend the practices from that assignment due to several issues:

  • The simplest way to pass the test is with static mutable fields, and these are generally not recommended.
  • Using serialization to produce deep copies might be appropriate in some cases, but I would generally recommend against it. Reason is that not all types would be expected to be serializable, and that deep copies might be expected to be fairly cheep to construct.
  • The instructions suggest that writing to files are expected. Unit tests should in general avoid writing to disk since disk is comparably slow, and unit tests need to run fast to be useful.
  • I find it fairly rare for copies to be needed. In many cases, immutable objects are easier to use, and does not need to be copied.
  • The test seem rather nonsensical overall. If I saw that in the wild it would trigger quite a few WTFs.
JonasH
  • 28,608
  • 2
  • 10
  • 23