C# 单元测试-安排测试项目无法访问的对象
我正在写一个纸牌游戏,试图学习Silverlight 我有一个游戏的域表示,它作为WCF服务公开给Silverlight,我的游戏对象上唯一的公共方法是“PlayCards”。这是一个看起来像这样的方法C# 单元测试-安排测试项目无法访问的对象,c#,unit-testing,C#,Unit Testing,我正在写一个纸牌游戏,试图学习Silverlight 我有一个游戏的域表示,它作为WCF服务公开给Silverlight,我的游戏对象上唯一的公共方法是“PlayCards”。这是一个看起来像这样的方法 public void PlayCards(Guid playerId, List<Card> cards) Hand类有不同的部分 public class Hand { public List<Card> FaceDownCards { ge
public void PlayCards(Guid playerId, List<Card> cards)
Hand类有不同的部分
public class Hand
{
public List<Card> FaceDownCards { get; internal set; }
public List<Card> FaceUpCards { get; internal set; }
public List<Card> InHandCards { get; internal set; }
public-class-Hand
{
公共列表面朝下卡片{get;internal set;}
公共列表FaceUpCards{get;internal set;}
Handcards中的公共列表{get;internal set;}
现在,在我的单元测试中,我想设置各种场景,其中一个玩家有特定的牌,下一个玩家有特定的牌。然后让第一个玩家玩一些牌(通过公共PlayCards方法),然后断言游戏状态
但当然,由于玩家是只读属性,我不能这样做。同样地,手(在玩家身上)是不可访问的。同样地,手的部分也是不可访问的
你知道我该怎么做吗
我想这可能意味着我的设计是错误的
谢谢
编辑:
下面是一些类的外观,让您了解我想在玩完牌后断言的一些属性
当我尝试InternalsToVisible时,我暂时将私有setter改为internal,但我对纯TDD的做事方式感兴趣
public class Game
{
public List<Player> Players { get; internal set; }
public Deck Deck { get; internal set; }
public List<Card> PickUpPack { get; internal set; }
public CardList ClearedCards { get; internal set; }
public Player CurrentPlayer
{
get
{
return Players.SingleOrDefault(o => o.IsThisPlayersTurn);
}
}
internal Direction Direction { get; set; }
..
public class Player
{
public Guid Id { get; internal set; }
public Game CurrentGame { get; internal set; }
public Hand Hand { get; internal set; }
public bool IsThisPlayersTurn { get; internal set; }
public bool IsAbleToPlay { get; internal set; }
public string Name { get; internal set; }
...
public class Hand
{
public List<Card> FaceDownCards { get; internal set; }
public List<Card> FaceUpCards { get; internal set; }
public List<Card> InHandCards { get; internal set; }
...
公共类游戏
{
公共列表玩家{get;internal set;}
公共甲板{get;内部集合;}
公共列表PickUpPack{get;内部集合;}
公共CardList ClearedCards{get;internal set;}
公共播放器
{
得到
{
返回玩家。单打或默认(o=>o.IsThisPlayersTurn);
}
}
内部方向{get;set;}
..
公开课选手
{
公共Guid Id{get;内部集合;}
公共游戏CurrentGame{get;内部集;}
公共手牌{get;内部集合;}
公共布尔值Isthisplayer返回{get;内部集合;}
公共布尔IsAbleToPlay{get;内部集;}
公共字符串名称{get;internal set;}
...
公务生
{
公共列表面朝下卡片{get;internal set;}
公共列表FaceUpCards{get;internal set;}
Handcards中的公共列表{get;internal set;}
...
我过去也遇到过同样的问题
看看这个班
这里有一个关于如何使用它的例子
此外,您可以考虑将类中的方法从
这种方法可能会带来更多的开销,但我认为从长远来看,它会有所帮助。我认为问题的关键在于: 我需要考虑很多情况 单元测试(通过UI进行测试是非常重要的 变得非常乏味,尤其是当 有很多场景都没有 但是, 要做到这一点,就意味着要作出各种努力 真正不需要的公共属性 需要(我的测试除外 目的) 我建议不要过于担心更改接口以支持测试 务必将set accessors保持在内部。*您可以限制对API的影响,因为您真正需要的是为需要排列的对象提供额外的公共构造函数。例如:
public Player(Guid id, Hand hand, bool isThisPlayersTurn, string name) { ... }
您希望能够编写简单、清晰的测试用例:
Hand hand = new Hand(faceDownCards, faceUpCards, inHandCards);
Player player = new Player(Guid.NewGuid(), hand, true, "Christo");
Game game = new Game(player);
我从不后悔这样做,即使只是为了测试目的。API仍然很清楚,人们使用正确的构造函数:通常,他们会使用默认构造函数(或者根本不使用构造函数-相反,他们会调用game.AddPlayer(“Christo”)
)并且仅使用扩展构造函数进行测试或反序列化(如果合适)
*并考虑改变成员的公共接口,如“代码>游戏”,玩家<代码> >代码> iQueDebug 以更好地传达只读语义。
这不是你的设计错误,但你的实现可能是。试试这个,接口只在属性声明上有<代码> GeultTes:public class Game : IGame
{
public List<IPlayer> Players
{
get { return _players; }
}
}
public class Player : IPlayer
{
public IHand Hand { get; internal set; }
}
public class Hand : IHand
{
public List<Card> FaceDownCards { get; internal set; }
public List<Card> FaceUpCards { get; internal set; }
public List<Card> InHandCards { get; internal set; }
}
这不是一个非常可测试的类,因为您的测试无法设置任何内容。我发现解决这一问题的最佳方法是构建两个接口IGame
和ITestableGame
,它们以不同的方式公开属性:
public interface IGame
{
IPlayer NextPlayer { get; }
bool NextPlayerCanPlay { get; }
}
internal interface ITestableGame
{
IPlayer NextPlayer { get; set; }
bool NextPlayerCanPlay { get; set; }
}
public class Game : IGame, ITestableGame
{
public IPlayer NextPlayer { get; set; }
public bool NextPlayerCanPlay { get; set; }
}
然后,在您的服务中,只需向客户端发送一个IGame
对象,或者将ITestableGame
接口设置为内部接口,并将其作为InternalsVisibleTo(TestAssembly)
进行营销,或者将其公开,在测试之外不要使用它
编辑3
仅根据您发布的内容,听起来您的控制流是这样设置的:
public class Game
{
public Player NextPlayer { get; private set; }
public bool NextPlayerCanPlay { get; private set; }
...
}
public class Player
{
public void Play(List<Card> cardsToPlay)
{
hand.InHandCards.Remove(cardsToPlay);
currentGame.PickUpPack.Add(cardsToPlay);
hand.Add(currentGame.Deck.Draw(cardsToPlay.Count));
currentGame.SelectNextPlayer();
}
}
公共类播放器
{
公共无效播放(列表卡片停止播放)
{
手持卡。移除(卡停止播放);
currentGame.PickUpPack.Add(cardsToPlay);
增加(当前游戏.牌组.抽牌(牌组.计数));
currentGame。选择下一层();
}
}
这相当准确吗?是的,我知道。谢谢。这可能是我要走的路。但我知道这会受到纯粹主义者的负面影响。我想听听他们怎么说。即使是“你的设计全错了”,这对道具行得通吗
public class Game
{
public Player NextPlayer { get; private set; }
public bool NextPlayerCanPlay { get; private set; }
...
}
public interface IGame
{
IPlayer NextPlayer { get; }
bool NextPlayerCanPlay { get; }
}
internal interface ITestableGame
{
IPlayer NextPlayer { get; set; }
bool NextPlayerCanPlay { get; set; }
}
public class Game : IGame, ITestableGame
{
public IPlayer NextPlayer { get; set; }
public bool NextPlayerCanPlay { get; set; }
}
public class Player
{
public void Play(List<Card> cardsToPlay)
{
hand.InHandCards.Remove(cardsToPlay);
currentGame.PickUpPack.Add(cardsToPlay);
hand.Add(currentGame.Deck.Draw(cardsToPlay.Count));
currentGame.SelectNextPlayer();
}
}