Asp.net 这是测试演示者的正确方法吗
我正在使用web表单和MVP模式在三层架构中创建一个购物网站。我还决定在presenter类中进行验证和类型转换。对于测试框架,我使用NUnit,对于模拟,我使用NSubstitute。这是我的类别模型类:Asp.net 这是测试演示者的正确方法吗,asp.net,unit-testing,testing,webforms,mvp,Asp.net,Unit Testing,Testing,Webforms,Mvp,我正在使用web表单和MVP模式在三层架构中创建一个购物网站。我还决定在presenter类中进行验证和类型转换。对于测试框架,我使用NUnit,对于模拟,我使用NSubstitute。这是我的类别模型类: //we're doing Dependency injection here. public abstract class BaseRepository { EntityContext context; public BaseRepo
//we're doing Dependency injection here.
public abstract class BaseRepository
{
EntityContext context;
public BaseRepository()
{
context = new EntityContext();
}
public EntityContext Context
{
get { return context; }
}
}
public class CategoryRepository : BaseRepository
{
public int Add(long id, string name)
{
Category cat = new Category();
cat.Id = id;
cat.Name = name;
Context.Category.Add(cat);
Context.SaveChanges();
}
}
以下是类别演示者:
public class CategoryPresenter : BasePresenter //has nothing but a dependency property to Logger
{
BaseRepository _model;
IView _view;
public CategoryPresenter(IView view)
{
_model = new CategoryRepository();
_view = view;
}
public void Add()
{
//havn't passed the tests yet since i'm not sure if i'm on the correct path.
//whatever validation, loggin and type casting will go here.
_model.Add(_view.CategoryId, _view.CategoryName);
}
}
[Test]
public void Add_NullId_ThrowException()
{
_view.CategoryId.Returns(p => null);
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_EmptyId_ThrowException()
{
_view.CategoryId.Returns(p => "");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_SpaceOnlyId_ThrowException()
{
_view.CategoryId.Returns(p => " ");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_InvalidLowBoundId_ThrowException()
{
_view.CategoryId.Returns(p => "-1");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_InvalidHighBoundId_ThrowException()
{
_view.CategoryId.Returns(p => long.MaxValue.ToString() + "1");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_EmptyName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => "");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_NullName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => null);
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_SpaceOnlyName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => " ");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_NumberOnlyName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => "123");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
下面是演示者的测试课程:
public class CategoryPresenter : BasePresenter //has nothing but a dependency property to Logger
{
BaseRepository _model;
IView _view;
public CategoryPresenter(IView view)
{
_model = new CategoryRepository();
_view = view;
}
public void Add()
{
//havn't passed the tests yet since i'm not sure if i'm on the correct path.
//whatever validation, loggin and type casting will go here.
_model.Add(_view.CategoryId, _view.CategoryName);
}
}
[Test]
public void Add_NullId_ThrowException()
{
_view.CategoryId.Returns(p => null);
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_EmptyId_ThrowException()
{
_view.CategoryId.Returns(p => "");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_SpaceOnlyId_ThrowException()
{
_view.CategoryId.Returns(p => " ");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_InvalidLowBoundId_ThrowException()
{
_view.CategoryId.Returns(p => "-1");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_InvalidHighBoundId_ThrowException()
{
_view.CategoryId.Returns(p => long.MaxValue.ToString() + "1");
_view.CategoryName.Returns(p => "test");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_EmptyName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => "");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_NullName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => null);
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_SpaceOnlyName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => " ");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
[Test]
public void Add_NumberOnlyName_ThrowException()
{
_view.CategoryId.Returns(p => "1");
_view.CategoryName.Returns(p => "123");
Assert.Throws(typeof(InvalidOperationException), _presenter.Add());
}
我的测试正确吗?我的意思是,这就是测试类的样子吗?我错过了什么?这是不是太多了?比如“您不需要测试空性”或者与我的测试或代码相关的任何其他问题?如果您注意到我的整个代码和/或体系结构中有任何错误,如果您纠正我的错误,我将不胜感激。谢谢
更新:IView由.aspx页面继承。在“代码隐藏”中,我只需从单击事件的内部调用presenter方法,用户按下按钮就会触发该事件。至于记忆,我还没走那么远。只是停留在TDD上。我将从应用程序层(演示者所在的层)删除验证逻辑,并将其提取到域层(存储库所在的层) 然后不要在演示者中进行验证,而是让演示者调用必要的验证器 对于演示者的单元测试,您向演示者提供验证器模拟对象,并验证是否为数据调用了正确的验证方法 因此,您必须测试两件事: 1) 测试演示者是否使用视图中的数据调用验证程序 2) 自己测试验证器 测试可能如下所示: 对于演示者(类类别演示测试):
[测试]
public void Add_调用来自视图()的带有数据的验证器
{
_viewMock.CategoryId.Returns(p=>“id”);
_返回(p=>“name”);
_Add();
_categoryValidatorMock.Verify(x=>x.Validate(“id”,“name”),Times.Once);
}
[测试]
public void Add_ForwardsValidationExceptions()
{
_viewMock.CategoryId.Returns(p=>“id”);
_返回(p=>“name”);
_categoryValidatorMock.Setup(x=>x.Validate(…).Throws();
Assert.Throws(()=>\u presenter.Add());
}
请注意,我们不关心来自视图的具体输入,只关心使用来自视图的确切数据调用验证器,并将结果(在本例中为异常或无异常)传回
对于验证器(类CategoryValidatorTests。基本上所有当前测试都在这里):
[测试]
public void NullId_ThrowsException(){
字符串id=null;
string name=“test”;
抛出(()=>_validator.Validate(id,name));
}
注意,我不知道NSubstitutes语法,所以上面是伪代码。。希望你能破译:)
除此之外,我不会在演示者中创建存储库,而是通过构造函数注入它们的接口(就像您对IView所做的那样)。然后提供模拟对象,与验证程序一样,验证演示者是否正确调用了它们
以上所有这些都应该允许您在演示者之外重用验证逻辑,这将减少演示者的复杂性,使他们能够更加专注于在模型和视图之间进行调解以及处理工作流的实际目的。我将从应用程序层删除验证逻辑(演示者所在的位置)并将其提取到域层(存储库所在的位置) 然后不要在演示者中进行验证,而是让演示者调用必要的验证器 对于演示者的单元测试,您向演示者提供验证器模拟对象,并验证是否为数据调用了正确的验证方法 因此,您必须测试两件事: 1) 测试演示者是否使用视图中的数据调用验证程序 2) 自己测试验证器 测试可能如下所示: 对于演示者(类类别演示测试):
[测试]
public void Add_调用来自视图()的带有数据的验证器
{
_viewMock.CategoryId.Returns(p=>“id”);
_返回(p=>“name”);
_Add();
_categoryValidatorMock.Verify(x=>x.Validate(“id”,“name”),Times.Once);
}
[测试]
public void Add_ForwardsValidationExceptions()
{
_viewMock.CategoryId.Returns(p=>“id”);
_返回(p=>“name”);
_categoryValidatorMock.Setup(x=>x.Validate(…).Throws();
Assert.Throws(()=>\u presenter.Add());
}
请注意,我们不关心来自视图的具体输入,只关心使用来自视图的确切数据调用验证器,并将结果(在本例中为异常或无异常)传回
对于验证器(类CategoryValidatorTests。基本上所有当前测试都在这里):
[测试]
public void NullId_ThrowsException(){
字符串id=null;
string name=“test”;
抛出(()=>_validator.Validate(id,name));
}
注意,我不知道NSubstitutes语法,所以上面是伪代码。。希望你能破译:)
除此之外,我不会在演示者中创建存储库,而是通过构造函数注入它们的接口(就像您对IView所做的那样)。然后提供模拟对象,与验证程序一样,验证演示者是否正确调用了它们
以上所有这些都应该允许您在演示者之外重用验证逻辑,这将减少演示者的复杂性,使他们能够更加专注于在模型和视图之间进行调解以及处理工作流的实际目的。谁继承了IView?谁将内存发送到IView?请参阅更新。“内存”是指检索到的数据,对吗?谁继承了IView?谁将内存发送到IView?请参阅更新。“内存”是指检索到的数据,对吗?首先>如果我注入存储库