IRepository 和相关数据?
IRepository and Related Data?
几个星期前,我刚刚接受了一次工作面试测试,问题是我几乎解决了所有问题,除了一点,在这一点上,我想这是不可能解决的。但我肯定是错的。
本题涉及相关数据。我们的服务器 API,IRepository,只会 return 一个节点及其直接子节点(例如,假设 FakeRepository 正在从数据库加载。您不能为此测试更改 FakeRepository 中的代码)。
假设 NodeManager 是客户端代码。
We want to make sure that there is only ever one instance of a specific object on the client, so that our client has a consistent view of data in our application. The test “LoadingNodeB_ShouldAlwaysReturnTheSameInstance()” demonstrates this problem. Modify the code in the NodeManager so that this test passes.
所以,我们有这个 IRepo
namespace TestRecruitment.Repository
{
public interface IRepository
{
Node GetNodeAndImmediateChildren(string nodeName);
}
}
在一个测试项目中,我们有一个加载信息的假存储库。
using System;
using TestRecruitment.Repository;
namespace TestRecruitment.Test.Repository
{
public class FakeRepository : IRepository
{
/// <summary>
/// YOU MUST NOT CHANGE THIS METHOD
/// </summary>
public Node GetNodeAndImmediateChildren(string nodeName)
{
switch (nodeName)
{
case "Node A":
// do not modify this
var nodeB = new Node { Name = "Node B" };
var nodeC = new Node { Name = "Node C" };
return new Node { Name = "Node A", ImmediateChildren = new[] { nodeB, nodeC } };
case "Node B":
// do not modify this
var nodeD = new Node { Name = "Node D" };
var nodeE = new Node { Name = "Node E" };
return new Node { Name = "Node B", ImmediateChildren = new[] { nodeD, nodeE } };
case "Node E":
var nodeA = new Node { Name = "Node A" };
var nodeF = new Node { Name = "Node F" };
return new Node { Name = "Node E", ImmediateChildren = new[] { nodeA, nodeF } };
default:
throw new ApplicationException("Unknown node");
}
}
}
}
问题是您只能更改存储库,不能触及任何其他代码。
using System.Linq;
namespace TestRecruitment.Repository
{
public class NodeManager
{
private readonly IRepository _nodeRepository;
public NodeManager(IRepository nodeRepository)
{
_nodeRepository = nodeRepository;
}
public Node GetNodeAndImmediateChildren(string name)
{
return _nodeRepository.GetNodeAndImmediateChildren(name);
}
}
}
嗯,就是这样。
任何帮助将不胜感激,我只是想知道如何解决它。
我创建了一个 github 存储库 https://github.com/rothariger/TestRecruitment
此致!
假设节点由其名称唯一标识,确保您 return 同一实例的一种方法是在客户端保留本地缓存并每次维护 Node.ImmediateChildren
集合调用存储库:
public class NodeManager
{
private readonly IRepository _nodeRepository;
private readonly Dictionary<string, Node> _cachedNodes = new Dictionary<string, Node>();
public NodeManager(IRepository nodeRepository)
{
_nodeRepository = nodeRepository;
}
public Node GetNodeAndImmediateChildren(string name)
{
var repositoryNode =_nodeRepository.GetNodeAndImmediateChildren(name);
UpdateCache(repositoryNode);
return _cachedNodes[repositoryNode.Name];
}
private void UpdateCache(Node repositoryNode)
{
AddOrUpdateChildrenCollectionInCache(repositoryNode);
foreach (var childNode in repositoryNode.ImmediateChildren)
{
AddOrUpdateChildrenCollectionInCache(childNode);
}
}
private void AddOrUpdateChildrenCollectionInCache(Node repoNode)
{
if (_cachedNodes.TryGetValue(repoNode.Name, out var cachedNode))
{
cachedNode.ImmediateChildren = repoNode.ImmediateChildren;
}
else
{
_cachedNodes.Add(repoNode.Name, repoNode);
}
}
}
几个星期前,我刚刚接受了一次工作面试测试,问题是我几乎解决了所有问题,除了一点,在这一点上,我想这是不可能解决的。但我肯定是错的。
本题涉及相关数据。我们的服务器 API,IRepository,只会 return 一个节点及其直接子节点(例如,假设 FakeRepository 正在从数据库加载。您不能为此测试更改 FakeRepository 中的代码)。
假设 NodeManager 是客户端代码。
We want to make sure that there is only ever one instance of a specific object on the client, so that our client has a consistent view of data in our application. The test “LoadingNodeB_ShouldAlwaysReturnTheSameInstance()” demonstrates this problem. Modify the code in the NodeManager so that this test passes.
所以,我们有这个 IRepo
namespace TestRecruitment.Repository
{
public interface IRepository
{
Node GetNodeAndImmediateChildren(string nodeName);
}
}
在一个测试项目中,我们有一个加载信息的假存储库。
using System;
using TestRecruitment.Repository;
namespace TestRecruitment.Test.Repository
{
public class FakeRepository : IRepository
{
/// <summary>
/// YOU MUST NOT CHANGE THIS METHOD
/// </summary>
public Node GetNodeAndImmediateChildren(string nodeName)
{
switch (nodeName)
{
case "Node A":
// do not modify this
var nodeB = new Node { Name = "Node B" };
var nodeC = new Node { Name = "Node C" };
return new Node { Name = "Node A", ImmediateChildren = new[] { nodeB, nodeC } };
case "Node B":
// do not modify this
var nodeD = new Node { Name = "Node D" };
var nodeE = new Node { Name = "Node E" };
return new Node { Name = "Node B", ImmediateChildren = new[] { nodeD, nodeE } };
case "Node E":
var nodeA = new Node { Name = "Node A" };
var nodeF = new Node { Name = "Node F" };
return new Node { Name = "Node E", ImmediateChildren = new[] { nodeA, nodeF } };
default:
throw new ApplicationException("Unknown node");
}
}
}
}
问题是您只能更改存储库,不能触及任何其他代码。
using System.Linq;
namespace TestRecruitment.Repository
{
public class NodeManager
{
private readonly IRepository _nodeRepository;
public NodeManager(IRepository nodeRepository)
{
_nodeRepository = nodeRepository;
}
public Node GetNodeAndImmediateChildren(string name)
{
return _nodeRepository.GetNodeAndImmediateChildren(name);
}
}
}
嗯,就是这样。
任何帮助将不胜感激,我只是想知道如何解决它。
我创建了一个 github 存储库 https://github.com/rothariger/TestRecruitment
此致!
假设节点由其名称唯一标识,确保您 return 同一实例的一种方法是在客户端保留本地缓存并每次维护 Node.ImmediateChildren
集合调用存储库:
public class NodeManager
{
private readonly IRepository _nodeRepository;
private readonly Dictionary<string, Node> _cachedNodes = new Dictionary<string, Node>();
public NodeManager(IRepository nodeRepository)
{
_nodeRepository = nodeRepository;
}
public Node GetNodeAndImmediateChildren(string name)
{
var repositoryNode =_nodeRepository.GetNodeAndImmediateChildren(name);
UpdateCache(repositoryNode);
return _cachedNodes[repositoryNode.Name];
}
private void UpdateCache(Node repositoryNode)
{
AddOrUpdateChildrenCollectionInCache(repositoryNode);
foreach (var childNode in repositoryNode.ImmediateChildren)
{
AddOrUpdateChildrenCollectionInCache(childNode);
}
}
private void AddOrUpdateChildrenCollectionInCache(Node repoNode)
{
if (_cachedNodes.TryGetValue(repoNode.Name, out var cachedNode))
{
cachedNode.ImmediateChildren = repoNode.ImmediateChildren;
}
else
{
_cachedNodes.Add(repoNode.Name, repoNode);
}
}
}