C# 如何在代码中找到单元测试必须覆盖的位置
我知道在实际编写代码之后再编写测试并不太好。我是单元测试新手,觉得单元测试可能会带来很多好的优势,所以我一直在想一个尽可能多的方法 例如,让我们使用以下代码:C# 如何在代码中找到单元测试必须覆盖的位置,c#,unit-testing,tdd,rhino-mocks,.net,C#,Unit Testing,Tdd,Rhino Mocks,.net,我知道在实际编写代码之后再编写测试并不太好。我是单元测试新手,觉得单元测试可能会带来很多好的优势,所以我一直在想一个尽可能多的方法 例如,让我们使用以下代码: public class ProjectsPresenter : IProjectsViewObserver { private readonly IProjectsView _view; private readonly IProjectsRepository _repository; public Proje
public class ProjectsPresenter : IProjectsViewObserver
{
private readonly IProjectsView _view;
private readonly IProjectsRepository _repository;
public ProjectsPresenter(IProjectsRepository repository, IProjectsView view)
{
_view = view;
_repository = repository;
Start();
}
public void Start()
{
_view.projects = _repository.FetchAll();
_view.AttachPresenter(this);
}
}
所以,看看上面的代码,你们能回答我通常应该对上面的代码编写哪些测试吗
我正在对构造函数进行写测试,以确保调用了存储库的FetchAll,并在视图站点AttachPresenter上调用了FetchAll
后期编辑 以下是我的视图界面:
public interface IProjectsView
{
List<Project> projects { set; }
Project project { set; }
void AttachPresenter(IProjectsViewObserver projectsPresenter);
}
公共接口IProjectsView
{
列出项目{set;}
项目{set;}
无效附件演示者(IProjectsViewObserver projectsPresenter);
}
以下是一个视图:
public partial class ProjectsForm : DockContent, IProjectsView
{
private IProjectsViewObserver _presenter;
public ProjectsForm()
{
InitializeComponent();
}
public Project project
{
set
{
listBoxProjects.SelectedItem = value;
}
}
public List<Project> projects
{
set
{
listBoxProjects.Items.Clear();
if ((value != null) && (value.Count() > 0))
listBoxProjects.Items.AddRange(value.ToArray());
}
}
public void AttachPresenter(IProjectsViewObserver projectsPresenter)
{
if (projectsPresenter == null)
throw new ArgumentNullException("projectsPresenter");
_presenter = projectsPresenter;
}
private void listBoxProjects_SelectedValueChanged(object sender, EventArgs e)
{
if (_presenter != null)
_presenter.SelectedProjectChanged((Project)listBoxProjects.SelectedItem);
}
}
公共部分类项目表单:DockContent,IProjectsView
{
私有IProjectsViewObserver_演示者;
公共项目表单()
{
初始化组件();
}
公共工程项目
{
设置
{
listBoxProjects.SelectedItem=value;
}
}
公开名单项目
{
设置
{
listBoxProjects.Items.Clear();
如果((value!=null)&&(value.Count()>0))
listBoxProjects.Items.AddRange(value.ToArray());
}
}
public void AttachPresenter(IProjectsViewObserver projectsPresenter)
{
if(projectsPresenter==null)
抛出新ArgumentNullException(“projectsPresenter”);
_演示者=projectsPresenter;
}
private void listBoxProjects\u SelectedValueChanged(对象发送者,事件参数e)
{
如果(_presenter!=null)
_presenter.SelectedProjectChanged((项目)listBoxProjects.SelectedItem);
}
}
后期编辑#2 这就是我如何测试与存储库的交互。一切都好吗
[Test]
public void ProjectsPresenter_RegularProjectsProcessing_ViewProjectsAreSetCorrectly()
{
// Arrange
MockRepository mocks = new MockRepository();
var view = mocks.StrictMock<IProjectsView>();
var repository = mocks.StrictMock<IProjectsRepository>();
List<Project> projList = new List<Project> {
new Project { ID = 1, Name = "test1", CreateTimestamp = DateTime.Now },
new Project { ID = 2, Name = "test2", CreateTimestamp = DateTime.Now }
};
Expect.Call(repository.FetchAll()).Return(projList);
Expect.Call(view.projects = projList);
Expect.Call(delegate { view.AttachPresenter(null); }).IgnoreArguments();
mocks.ReplayAll();
// Act
ProjectsPresenter presenter = new ProjectsPresenter(repository, view);
// Assert
mocks.VerifyAll();
}
[测试]
公共无效项目重置中心\常规项目处理\视图项目重置正确()
{
//安排
MockRepository mocks=新建MockRepository();
var view=mocks.StrictMock();
var repository=mocks.StrictMock();
列表项目列表=新列表{
新项目{ID=1,Name=“test1”,CreateTimestamp=DateTime.Now},
新项目{ID=2,Name=“test2”,CreateTimestamp=DateTime.Now}
};
Expect.Call(repository.FetchAll()).Return(projList);
Expect.Call(view.projects=projList);
Expect.Call(委托{view.AttachPresenter(null);}).IgnoreArguments();
mocks.ReplayAll();
//表演
ProjectsPresenter=新建ProjectsPresenter(存储库,视图);
//断言
mocks.VerifyAll();
}
我会在开始时添加一些简单的测试,比如:
参考检查null
返回任何值FetchAll()
不要在第一次添加大量测试代码,而是在开发代码发生变化后对其进行细化。我会添加异常测试,例如ArgumentException、corner Case和FetchAll()的常见测试 附注:start必须公开吗 我知道在实际编写代码之后再编写测试并不太好 总比根本不写测试好 您的方法使用两个外部组件,并且应该验证交互(除了前面提到的参数验证)。检查
FetchAll
是否被调用不会给您任何值(或者检查它会返回一些东西-这属于ProjectsRepository
测试本身)-您希望检查视图的项目是否被设置(这将间接检查FetchAll
是否被调用)。您需要的测试包括:
- 验证视图项目是否设置为预期值
- 验证是否已附加演示者
- 验证输入参数
Pex是一个有趣的工具,值得一试。它可以生成具有高代码覆盖率的单元测试套件:。它不会取代您自己对代码的了解,以及哪些测试场景对您来说比其他人更重要,但它是一个很好的补充。在编写生产代码之前编写测试的目的首先是让您(开发人员)处于“我如何知道我的代码何时工作?”当您的开发关注于工作代码的结果,而不是代码本身时,您关注的是通过代码获得的实际业务价值,而不是无关的问题(数百万工时用于构建和维护用户从未要求、想要或需要的功能)。当您这样做时,您正在进行“测试驱动开发” 如果你在做纯TDD,答案是100%的代码覆盖率。也就是说,您不会编写一行单元测试代码尚未涵盖的生产代码 在VisualStudio中,如果您转到测试->分析代码覆盖率,它将显示您尚未覆盖的所有代码行
实际上,实施100%的代码覆盖率并不总是可行的。还有一些代码行比其他代码行重要得多。确定哪一条线再次取决于每条线提供的业务价值以及该线失败的后果。某些行(如日志记录)的影响可能比其他行小 更好的问题是start()是否在构造函数中被调用。空引用检查似乎是个好主意!谢谢我不太清楚您关于“FetchAll()返回任何值”的观点。您能更广泛地描述一下吗?@kseen:我的意思是,检查
FetchAll()
是否在\u view.projects=\u repository.FetchAll()中返回任何值代码>。换句话说,如果程序能够
// "RegularProcessing" in test name feels a bit forced;
// in such cases, you can simply skip 'conditions' part of test name
public void ProjectsPresenter_SetsViewProjectsCorrectly()
{
var view = MockRepository.GenerateMock<IProjectView>();
var repository = MockRepository.GenerateMock<IProjectsRepository>();
// Don't even need content;
// reference comparison will be enough
List<Project> projects = new List<Project>();
// We use repository in stub mode;
// it will simply provide data and that's all
repository.Stub(r => r.FetchAll()).Return(projects);
view.Expect(v => v.projects = projects);
ProjectsPresenter presenter = new ProjectsPresenter(repository, view);
view.VerifyAllExpecations();
}
public void ProjectsPresenter_AttachesPresenterToView()
{
// Arrange
var view = MockRepository.GenerateMock<IProjectView>();
view.Expect(v => v.AttachPresenter(Arg<IProjectsViewObserver>.Is.Anything));
var repository = MockRepository.GenerateMock<IProjectsRepository>();
// Act
var presenter = new ProjectsPresenter(repository, view);
// Assert
view.VerifyAllExpectations();
}