需要单元测试和最佳实践的保证
我已经 7 个月没有进行 TDD 和单元测试了,我有点忘记了。我现在在店里想要开始做,但我是那里唯一的人 并不完全是这方面的大师。
我有点生疏了,我收到各种各样的问题,很多时候我无法给出正确的答案。
我收到的典型问题:
我没有发现任何问题 集成测试?我告诉他们是 慢,你永远不应该这样做。
如果我 无法测试 privateMethod (我知道 MSTest 确实)有什么意义 测试?我所有重要的方法都是 私人的。
我不明白建立一个 期望并返回一个结果 测试满意吗?
您进行的典型单元测试是什么 应该在每一层执行?应该 您只在边界级别进行测试吗?
如何 我要测试我的存储过程返回吗 预期的结果?
您认为以下测试对您有意义吗?您通常会在每一层进行什么样的测试?有代码示例吗?
我做了 3 种测试
1)ViewModel 测试。
2)Wcf 通过模拟服务进行测试
3)Wcf Integratontest 但模拟 Dal
这是你所做的吗?如果你认为这是错误的,你能纠正我吗?你能改进它们吗?
视图模型测试 属性已改变 和方法已在下面调用示例
//property has changed
[TestMethod]
public void Should_be_able_to_test_that_customer_description_propertyChanged_was_raised()
{
//act
var customerResponse=new CustomerResponse{Description = "Test"};
var customerViewModel = new CustomerViewModel(customerResponse);
var eventWasRaised = false;
customerViewModel.PropertyChanged += (sender, e) => eventWasRaised = e.PropertyName == "Description";
customerViewModel.Description = "DescriptionTest";
Assert.IsTrue(eventWasRaised, "PropertyChanged event was not raised correctly.");
}
//Testing a method on the view model has been called
[Test]
public void Should_be_able_to_test_that_insert_method_on_view_Model_has_been_executed()
{
var mock = new Mock<IRepository>();
var employeeVm = new EmployeeVM(mock.Object) {Age = 19};
employeeVm.SaveCommand.Execute(null);
mock.Verify(e=>e.Insert(It.IsAny<Employee>()));
}
WCF 单元测试
// 测试 1 模拟服务
[TestMethod]
public void Should_be_able_to_verify_getCustomer_has_been_called)
{
var mockService = new Mock<ICustomer>();
var expectedCustomer=new Customer{Id=1,Name="Jo"};
mockService.Setup(x => x.GetCustomer(It.IsAny<int>())).Returns(expectedCustomer);
var customerViewModel = new customerViewModel(mockService.Object);
customerViewModel.GetCustomer.Execute(null);
mockService.Verify(x=>x.GetCustomer(),Times.AtLeastOnce());
}
//Test 2 mocking the repository
[TestMethod]
public void Should_be_able_to_verify_getCustomer_has_been_called_on_the_service)
{
var mockRepository = new Mock<IRepositoryCustomer>();
var expectedCustomer=new Customer{Id=1,Name="Jo"};
mockRepository.Setup(x => x.GetCustomer(It.IsAny<int>())).Returns(expectedCustomer);
var customerService = new CustomerService(mock.Object);
customerService.GetCustomer(1);
mockRepository.Verify(x=>x.GetCustomer(),Times.AtLeastOnce());
}
I have not been doing TDD and Unit Tests for 7 months now and I kind of forgot. I am now in shop that wants to start doing it but I am the only one there
and not exactly a guru in the matter.
I am a bit rusty and I am getting all sorts of questions and many times I cannot give a proper answer.
Typical questions I get:
I dont see anything wrong with
integration Testing? I told them is
slow ,you should never do it.If I
cannot test privateMethod (I know
MSTest does) what is the point in
testing? All my important methods are
private.I dont see the point of setting up an
expectation and return a result that
pleases the test?What are the typical unit tests you
should perform in each layer? Should
you test only at boundary levels?How
do I test my Stored Procedure return
the intended results?
Do you think the below tests make any sense to you?What kind of test would you generally do at each layer?Any examples with code?
I do 3 kinds of tests
1)ViewModel Tests.
2)Wcf Tests by mocking the service
3)Wcf Integratontest but mocking the Dal
Is this what you do?.Can you correct me if yoou thing this is wrong.Can you improve them?
ViewModel tests
property has changed
and methods have been called example below
//property has changed
[TestMethod]
public void Should_be_able_to_test_that_customer_description_propertyChanged_was_raised()
{
//act
var customerResponse=new CustomerResponse{Description = "Test"};
var customerViewModel = new CustomerViewModel(customerResponse);
var eventWasRaised = false;
customerViewModel.PropertyChanged += (sender, e) => eventWasRaised = e.PropertyName == "Description";
customerViewModel.Description = "DescriptionTest";
Assert.IsTrue(eventWasRaised, "PropertyChanged event was not raised correctly.");
}
//Testing a method on the view model has been called
[Test]
public void Should_be_able_to_test_that_insert_method_on_view_Model_has_been_executed()
{
var mock = new Mock<IRepository>();
var employeeVm = new EmployeeVM(mock.Object) {Age = 19};
employeeVm.SaveCommand.Execute(null);
mock.Verify(e=>e.Insert(It.IsAny<Employee>()));
}
WCF Unit Tests
// Test 1 mocking the service
[TestMethod]
public void Should_be_able_to_verify_getCustomer_has_been_called)
{
var mockService = new Mock<ICustomer>();
var expectedCustomer=new Customer{Id=1,Name="Jo"};
mockService.Setup(x => x.GetCustomer(It.IsAny<int>())).Returns(expectedCustomer);
var customerViewModel = new customerViewModel(mockService.Object);
customerViewModel.GetCustomer.Execute(null);
mockService.Verify(x=>x.GetCustomer(),Times.AtLeastOnce());
}
//Test 2 mocking the repository
[TestMethod]
public void Should_be_able_to_verify_getCustomer_has_been_called_on_the_service)
{
var mockRepository = new Mock<IRepositoryCustomer>();
var expectedCustomer=new Customer{Id=1,Name="Jo"};
mockRepository.Setup(x => x.GetCustomer(It.IsAny<int>())).Returns(expectedCustomer);
var customerService = new CustomerService(mock.Object);
customerService.GetCustomer(1);
mockRepository.Verify(x=>x.GetCustomer(),Times.AtLeastOnce());
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,让我们看看我是否可以回答
集成测试现在是一个超载的术语。
当您编写单元测试时,您希望用假货/模拟来代替耗时/不可预测/昂贵的真实协作者,以便您可以专注于自己的代码(并假设真实的协作满足假定的合同)。这可以帮助您在很短的时间内运行单元测试,从而获得更快的反馈和进度。另外,测试失败现在表明您的代码中存在错误。相反,任何依赖项中的任何错误都可能导致您的测试失败
您还需要其他(缓慢的)测试来验证真正的协作(例如 DAL)是否按照合同。 (我现在倾向于将这些称为集成测试)
私有方法应该通过使用它们的公共接口进行测试。为调用私有方法的公共方法编写测试。如果无法做到这一点,则私有方法或其部分可能是多余的。
请参阅答案#1 - 您假设真正的依赖项将按照商定的合同运行。这使您可以专注于使用依赖项编写的代码。
单元测试应该测试对象,验收测试验证所有对象在相互插入时是否可以一起工作
编写一个测试,针对已知的参考数据库执行 DAL 并验证预期结果。这应该被标记为缓慢的集成测试(根据我选择的定义)。
Ok let's see if I can answer
Integration tests is an overloaded term now.
When you're writing unit tests, you want to substitute fakes/mocks for timeconsuming/unpredictable/expensive real collaborators so that you can focus on your own code (and assume that the real collabs satisfy an assumed contract). This can help you run your unit tests in a fraction of the time leading to faster feedback and progress. Also a test failure now indicates an error in your code.. the converse being any error in any dependency can cause your test to fail
You also need other (slow) tests that verify if the real collabs (e.g. the DAL) behave as per the contract. (I tend to call these integration tests now)
Private methods should be tested via the public interface which exercises them. Write tests for the public methods which call the private methods.. If this cannot be done, maybe the private methods or parts of it are redundant.
See answer#1- you're assuming that the real dependencies will behave as per an agreed contract. This allows you to focus on the code you're writing using the dependencies.
Unit tests should test objects, Acceptance tests verify that all the objects work together when plugged into each other
Write a test that exercises the DAL against a known reference database and verify the expected results. This should be tagged as a slow integration test (as per my chosen definition).
您编写的测试是一个很好的开始!尝试、练习和弄清楚什么有效、什么无效,是任何一个“大师”首先成为“大师”的方式。 (我还没有遇到任何“大师”;只是有多年实践的人)。
有几个问题,我将依次回答。
是的,集成测试确实很慢。
我通常对整个应用程序(从 GUI 或网页)针对整个系统的某些关键场景执行此操作,因为手动执行相同的测试非常耗时。随着应用程序的增长,测试人员必须执行的回归测试量也会增加。您可以通过编写这些自动化测试来帮助他们。
开发人员几乎看不到自动化测试的好处,因为真正需要它们并使用它们的是测试人员。站在他们的角度思考,你可能会看到更多的价值。
实际上,首先导出场景可能很有价值,因为它可以帮助开发人员、测试人员和分析师发现并解决他们对系统理解中的差异。
测试私有方法应该是不必要的。但是...
如果您的方法很复杂,您始终可以将其拆分为不同的类,并让您的类与该类协作。如果您的私有方法很重要,那么您可能应该这样做。
另外,不要测试方法。描述班级行为的各个方面,说明其价值的原因并给出一些使用它的示例。行为可能涉及不止一种方法。例如,
list.isEmpty
也要求我们使用list.add
;它们之间的交互对于使用list
来说非常重要。这也是我们不测试私有方法的原因 - 因为它们对于单独使用它们的类没有任何好处。
您的测试的名称可以帮助反映这一点。思考“我的视图模型应该......”,然后考虑它如何提供它所做的有价值的行为。例如,我会将您的第一个测试表述为“我的视图模型应该通知侦听器描述已更改”,因此
ShouldNotifyListenersThatTheDescriptionChanged
。不要设定期望,而是考虑您的班级有一些协作班级。
其中一些为班级提供信息——改变其行为的背景,产生不同的结果。他们中的一些人为班级做工作。第一个是“存根”,第二个是“模拟”(这里的术语在整个业务中是混合的)。
您不是设置期望,而是提供一个示例来显示该类在该上下文中的行为方式。
您不是要验证结果,而是要表明该类适当地委派了其职责。
模拟只是一种有用的方法。
我编写的典型测试可以帮助我描述代码的行为,确保其职责是适当的,并展示为什么代码是有价值的。这是大部分代码,但我不会为琐碎的类编写示例 - 例如,自定义异常、只是数据或属性的对象等。
您可以通过以下方式显示存储过程的行为:编写在不同上下文中使用它的示例,以显示行为的不同方面。您可能需要设置一些数据才能使其工作。与我合作的大多数团队都避免存储过程,只是因为测试它们很困难,或者他们只是依赖全栈场景来提供覆盖范围。
希望这会有所帮助,祝你好运!
The tests you've written are a pretty good start! Trying it out, practicing and working out what works and what doesn't is how anyone who is a 'guru' becomes one in the first place. (I've not met any 'gurus' yet; just people with years of practice).
There are a few questions so I'm going to answer them in turn.
Integration Testing is really slow, yes.
I normally do this for the whole application, from the Gui or web page, for certain key scenarios across the entire system, because performing the same tests manually is time consuming. As the application grows, so does the amount of regression testing which the testers will have to do. You can help them by writing these automated tests.
Developers hardly ever see the benefit of the automated tests, because it's the testers who really need them and use them. Think of it from their perspective and you may see more value.
Actually deriving the scenarios in the first place can be valuable because it helps developers, testers and analysts find and address differences in their understanding of the system.
Testing private methods should be unnecessary. However...
If your method is complex, you can always split it out into a different class, and make your class collaborate with that one. If your private methods are the important ones then you probably should do this.
Also, don't test methods. Describe each aspect of the behaviour of your class, show why it's valuable and give some examples of using it. Behaviour may involve more than one method. For instance,
list.isEmpty
requires us to work withlist.add
too; it's the interaction between them which is important for things usinglist
.This is also why we don't test private methods - because they're of no benefit to the class using them on their own.
The names of your tests could help to reflect this. Think "My view model should..." and then consider how it provides the valuable behaviour which it does. For instance, I would phrase your first test as "My View Model should notify listeners that the description changed", so
ShouldNotifyListenersThatTheDescriptionChanged
.Instead of setting up an expectation, consider that your class has some collaborating classes.
Some of them provide the class with information - contexts which change its behaviour, producing different outcomes. Some of them do jobs for the class. The first are "stubs", the second "mocks" (terminology here is mixed across the business).
Rather than setting up expectations, you're providing an example which shows how the class behaves within that context.
Rather than verifying an outcome, you're showing that the class delegates its responsibilities appropriately.
Mocks are just a useful way to do that.
The typical tests I write are those which help me describe the behaviour of the code, ensure its responsibilities are appropriate and show why the code is valuable. That's most of the code, but I won't write examples for trivial classes - for instance, custom exceptions, objects which are just data or properties, etc.
You can show the behaviour of a stored procedure by writing examples of using it in the different contexts which show the different aspects of behaviour. You may need to set up some data for this to work. Most teams I work with avoid stored procedures just because of the difficulty of testing them, or they simply rely on the full-stack scenarios to provide coverage.
Hope this helps, and best of luck!