Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Viewmodel的单元测试_C#_.net_Silverlight_Unit Testing_Tdd - Fatal编程技术网

C# Viewmodel的单元测试

C# Viewmodel的单元测试,c#,.net,silverlight,unit-testing,tdd,C#,.net,Silverlight,Unit Testing,Tdd,我是TDD的新手。我已经开始在视图模型上创建所需的属性,作为“纯自动”属性 public string Firstname { get; set; } 然后我创建一个测试 [TestMethod] [Tag("Property")] public void FirstNameTest() { ViewModel = new CustomerViewModel(); ViewModel.PropertyChanged += (s, e) =>

我是TDD的新手。我已经开始在视图模型上创建所需的属性,作为“纯自动”属性

public string Firstname { get; set; }
然后我创建一个测试

[TestMethod]
[Tag("Property")]
public void FirstNameTest()
{
    ViewModel = new CustomerViewModel();
    ViewModel.PropertyChanged += (s, e) =>
                                     {
                                         Assert.AreEqual("Firstname", e.PropertyName);
                                         Assert.AreEqual("Test", ViewModel.Firstname);
                                     };
    ViewModel.Firstname = "Test";
}
然后,我将扩展实际实现,使测试通过,如下所示:

public string Firstname
{
    get { return _contact.FirstName; }
    set
    {
        if (_contact.FirstName == value)
            return;

        _contact.FirstName = value;

        RaisePropertyChanged(() => Firstname);
    }
}
    [TestMethod]
    [Tag("Property")]
    public void FirstNameTest()
    {
        bool didFire = false;
        ViewModel = new CustomerViewModel();
        ViewModel.PropertyChanged += (s, e) =>
                                         {
                                             didFire = true;
                                             Assert.AreEqual("Firstname", e.PropertyName);
                                             Assert.AreEqual("Test", ViewModel.Firstname);
                                         };
        ViewModel.Firstname = "Test";
        Assert.IsTrue(didFire);
    }
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Foo.Example.Test
{
    [TestClass]
    public class Tests : SilverlightTest
    {

        // ... tests go here
    }
}

我的问题是Aut属性的测试仍然通过。有什么建议可以告诉我如何改进我的流程吗?

您需要进行另一项测试,以确认您的属性甚至发生了更改

当您进行该测试时,您的auto属性应该失败,因为事件永远不会触发


您可以这样做:

public string Firstname
{
    get { return _contact.FirstName; }
    set
    {
        if (_contact.FirstName == value)
            return;

        _contact.FirstName = value;

        RaisePropertyChanged(() => Firstname);
    }
}
    [TestMethod]
    [Tag("Property")]
    public void FirstNameTest()
    {
        bool didFire = false;
        ViewModel = new CustomerViewModel();
        ViewModel.PropertyChanged += (s, e) =>
                                         {
                                             didFire = true;
                                             Assert.AreEqual("Firstname", e.PropertyName);
                                             Assert.AreEqual("Test", ViewModel.Firstname);
                                         };
        ViewModel.Firstname = "Test";
        Assert.IsTrue(didFire);
    }
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Foo.Example.Test
{
    [TestClass]
    public class Tests : SilverlightTest
    {

        // ... tests go here
    }
}

除非测试的行为已经实现,否则测试应该失败

为了在我上一次尝试中测试属性更改通知,我创建了一个帮助我编写类似这样的测试(在NUnit中)


您可以尝试将测试编写为异步的。考虑这个测试方法:

[TestMethod]
[Asynchronous]
public void TestMethod1()
{
    TestViewModel testViewModel = new TestViewModel();

    bool firstNameChanged = false;

    testViewModel.PropertyChanged +=
        (s, e) =>
            {
                if (e.PropertyName == "FirstName")
                {
                    firstNameChanged = true;
                }
            };

    EnqueueCallback(() => testViewModel.FirstName = "first name");
    EnqueueConditional(() => firstNameChanged == true);
    EnqueueTestComplete();
}
请注意方法顶部的Asynchronous属性。这里有两个重要的方法:EnqueueCallback和EnqueueTestComplete。EnqueueCallback将向队列中添加lambda表达式,测试方法将等待当前回调执行。在本例中,我们订阅ViewModel上的PropertyChanged事件,并在FirstName属性通知更改时将局部布尔变量设置为true。然后,我们将两个回调排队:一个用于设置FirstName属性,另一个用于断言本地布尔变量的值已更改。最后,我们需要添加对EnqueueTestComplete()的调用,以便框架知道测试已经结束

注意:为了获得EnqueueCallback和EnqueueTestComplete,您需要在测试类上继承SilverlightTest。您还需要导入Microsoft.Silverlight.Testing以获取异步属性。它应该是这样的:

public string Firstname
{
    get { return _contact.FirstName; }
    set
    {
        if (_contact.FirstName == value)
            return;

        _contact.FirstName = value;

        RaisePropertyChanged(() => Firstname);
    }
}
    [TestMethod]
    [Tag("Property")]
    public void FirstNameTest()
    {
        bool didFire = false;
        ViewModel = new CustomerViewModel();
        ViewModel.PropertyChanged += (s, e) =>
                                         {
                                             didFire = true;
                                             Assert.AreEqual("Firstname", e.PropertyName);
                                             Assert.AreEqual("Test", ViewModel.Firstname);
                                         };
        ViewModel.Firstname = "Test";
        Assert.IsTrue(didFire);
    }
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Foo.Example.Test
{
    [TestClass]
    public class Tests : SilverlightTest
    {

        // ... tests go here
    }
}

以下是我过去是如何做到这一点的(我使用了NUnit,所以可能会有点不同):


也许这段代码还有更多的背景没有被揭示出来,但我看到的似乎是不必要的复杂。为什么要费心去钩住
RaisePropertyChanged
事件呢?设置属性后,只需检查属性

[TestMethod]
[Tag("Property")]
public void FirstNameTest()
{
    var expected = "John";
    var sut = new CustomerViewModel();

    sut.Firstname = expected;

    Assert.AreEqual(expected, sut.Firstname);
}

这也将把测试变成一个真正的单元测试。

非常感谢您给出了清晰的答案。现在可以了。但是,断言在最后一行抛出AssertFailedException。我必须F5它继续,然后我看到测试失败的结果。我正在使用VS2010附带的Silverlight 4单元测试工具包。这很烦人,是否可以抑制这种情况,如果出现问题,我不想稍后在50个单元测试中使用F5只是不要在调试模式下运行测试:)我在发行版下运行了它,但仍然会出现中断。这很烦人。我在Silverlight4测试框架下使用单元测试。有人知道吗?我找到了。这与调试模式无关答案是:@Antoine Aubry,或者他可以点击继续按钮或按F5。这是同样的行为。非常感谢这篇文章,我会很快研究它,看看我还能从中学到什么。不幸的是,链接已经死了,答案中没有复制这篇文章的信息。非常感谢。这个答案在Silverlight级别上对我帮助更大。然而,我想评论一件事,如果您使用EnqueueCallback而不使用任何EnqueueConditional的情况,这与您将调用同步是一样的。是的,应该使用EnqueueConditional使测试真正等待事件触发。我想我的例子太琐碎了,我道歉。它现在使用EnqueueConditional等待firstNamedChanged的布尔状态变为true。您不应该在lambda中放置断言。断言失败时抛出异常。如果您在lambda中这样做,那么这些将在被测试对象中激发,并且您将面临被对象处理的风险。相反,您应该将结果分配给测试范围中的一些(通常是bool)变量,然后在返回并解开调用堆栈时针对这些变量进行断言。这将有些无用。为什么框架能够正确处理自动属性的设置器?当您希望检查
PropertyChanged
事件是否按预期引发时,测试就开始有意义了。在这样的测试中,这是唯一值得检查的东西。@Martin我同意测试自动属性的设置器不会带来任何好处。但是,如果查看原始代码(由Hooman发布),您会注意到,只有当传入值不等于_contact.FirstName中的值时,才会设置该属性。这就是我的重构测试所涉及的代码部分。