最近我一直在努力改进我的单元测试,并且真正让我感到困惑的UT的“规则”之一是“每次测试的一个断言”。
我很想知道人们是否认为MS在断言这个测试方面做了正确的事情(忽略缺乏模拟等)。根据我目前的理解,这个例子应该真正执行一个需要测试的每个对象属性的创建调用(而不是一个调用和多个断言)。我做出这个假设是否正确?
方法取自:http://msdn.microsoft.com/en-us/vs2010trainingcourse_aspnetmvc3testing_topic4
[TestMethod()]
[DeploymentItem("MvcMusicStore.mdf")]
[DeploymentItem("MvcMusicStore_log.ldf")]
public void CreateTest()
{
using (TransactionScope ts = new TransactionScope())
{
StoreManagerController target = new StoreManagerController();
Album album = new Album()
{
GenreId = 1,
ArtistId = 1,
Title = "New Album",
Price = 10,
AlbumArtUrl = "/Content/Images/placeholder.gif"
};
ActionResult actual;
actual = target.Create(album);
Assert.IsTrue(album.AlbumId != 0);
MusicStoreEntities storeDB = new MusicStoreEntities();
var newAlbum = storeDB.Albums.SingleOrDefault(a => a.AlbumId == album.AlbumId);
Assert.AreEqual(album.GenreId, newAlbum.GenreId);
Assert.AreEqual(album.ArtistId, newAlbum.ArtistId);
Assert.AreEqual(album.Title, newAlbum.Title);
Assert.AreEqual(album.Price, newAlbum.Price);
Assert.AreEqual(album.AlbumArtUrl, newAlbum.AlbumArtUrl);
}
}
版本将类似于(复制相册对象上的每个属性)
[TestMethod()]
public void CreateTest_AlbumUrl()
{
// ** Arrange
var storeDB = new Mock<MusicStoreEntities>()
// Some code to setup the mocked store would go here
StoreManagerController target = new StoreManagerController(storeDB);
Album album = new Album()
{
GenreId = 1,
ArtistId = 1,
Title = "New Album",
Price = 10,
AlbumArtUrl = "/Content/Images/placeholder.gif"
};
// ** Act
actual = target.Create(album);
var newAlbum = storeDB.Albums.SingleOrDefault(a => a.AlbumId == album.AlbumId);
// ** Assert
Assert.AreEqual(album.AlbumArtUrl, newAlbum.AlbumArtUrl);
}
答案 0 :(得分:6)
这条规则经常被误解。它不是关于单个断言(如代码行/ Assert
调用),而是关于验证单个概念。在这种情况下,Microsoft验证了相册是否正确添加 - 相册是单一概念。
Roy Osherove's put it in very simple words:
我的指南通常是每次测试测试一个逻辑CONCEPT。你可以在同一个对象上有多个断言。它们通常与被测试的概念相同。
答案 1 :(得分:2)
这应该不是一个严格的规则,至多是一个经验法则。恕我直言,在许多情况下,将多个断言放入单个测试中会更简单,更容易。
应该在每个测试中测试单个故事/案例,但这可能需要多个断言来验证。恕我直言,创建多个几乎完全相同的测试只是为了满足&#34;规则&#34;。但这只是我个人的意见。我更倾向于坚持书本规则。
答案 2 :(得分:0)
你不应该从字面上理解这个规则,你应该只为每个测试断言一个行为,但你可能需要进行几次Assert
调用来断言一个行为。
在这种情况下,测试中的行为似乎是使用提供的信息创建相册。