使用xUnit为.net core程序进行单元测试(中)

发表于:2018-1-17 13:03

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:solenovex    来源:51Testing软件测试网采编

分享:
  Assert Null值
          [Fact]
          public void NotHaveNameByDefault()
          {
              var plumber = new Plumber();
              Assert.Null(plumber.Name);
          }
          [Fact]
          public void HaveNameValue()
          {
              var plumber = new Plumber
              {
                  Name = "Brian"
              };
              Assert.NotNull(plumber.Name);
          }
  有两个方法, Assert.Null 和 Assert.NotNull, 直接传入期待即可.
  测试会Pass的.
  集合 Collection Assert
  修改一下被测试类, 添加一个集合属性, 并赋值:
  namespace Hospital
  {
      public abstract class Worker
      {
          public string Name { get; set; }
          public abstract double TotalReward { get; }
          public abstract double Hours { get; }
          public double Salary => TotalReward / Hours;
          public List<string> Tools { get; set; }
      }
      public class Plumber : Worker
      {
          public Plumber()
          {
              Tools = new List<string>()
              {
                  "螺丝刀",
                  "扳子",
                  "钳子"
              };
          }
          public override double TotalReward => 200;
          public override double Hours => 3;
      }
  }
  测试是否包含某个元素, Assert.Contains():
          [Fact]
          public void HaveScrewdriver()
          {
              var plumber = new Plumber();
              Assert.Contains("螺丝刀", plumber.Tools);
          }
  Build, Run Test, 结果Pass.
  修改一下名字, 让其Fail:
  这个失败信息还是很详细的.
  相应的还有一个Assert.DoesNotContain()方法, 测试集合是否不包含某个元素.
          [Fact]
          public void NotHaveKeyboard()
          {
              var plumber = new Plumber();
              Assert.DoesNotContain("键盘", plumber.Tools);
          }
  这个test也会pass.
  Predicate:
  测试一下集合中是否包含符合某个条件的元素:

          [Fact]
          public void HaveAtLeastOneScrewdriver()
          {
              var plumber = new Plumber();
              Assert.Contains(plumber.Tools, t => t.Contains("螺丝刀"));
          }
  使用的是Assert.Contains的一个overload方法, 它的第一个参数是集合, 第二个参数是Predicate.
  Build, Run Test, 会Pass的.
  比较集合相等:
  添加Test:
          [Fact]
          public void HaveAllTools()
          {
              var plumber = new Plumber();
              var expectedTools = new []
              {
                  "螺丝刀",
                  "扳子",
                  "钳子"
              };
              Assert.Equal(expectedTools, plumber.Tools);
          }
  注意, Plumber的tools类型是List, 这里的expectedTools类型是array.
  这个test 仍然会Pass.
  如果修改一个元素, 那么测试会Fail, 信息如下:
  Assert针对集合的每个元素:
  如果想对集合的每个元素进行Assert, 当然可以通过循环来Assert了, 但是更好的写法是调用Assert.All()方法:
          [Fact]
          public void HaveNoEmptyDefaultTools()
          {
              var plumber = new Plumber();
              Assert.All(plumber.Tools, t => Assert.False(string.IsNullOrEmpty(t)));
          }
  这个测试会Pass.
  如果在被测试类的Tools属性添加一个空字符串, 那么失败信息会是:
  这里写到, 4个元素里面有1个没有pass.
  针对Object类型的Assert
   首先再添加一个Programmer类:
      public class Programmer : Worker
      {
          public override double TotalReward => 1000;
          public override double Hours => 3.5;
      }
  然后建立一个WorkerFactory:
  namespace Hospital
  {
      public class WorkerFactory
      {
          public Worker Create(string name, bool isProgrammer = false)
          {
              if (isProgrammer)
              {
                  return new Programmer { Name = name };
              }
              return new Plumber { Name = name };
          }
      }
  }
  判断是否是某个类型 Assert.IsType<Type>(xx):
  建立一个测试类 WorkerShould.cs和一个test:
  namespace Hospital.Tests
  {
      public class WorkerShould
      {
          [Fact]
          public void CreatePlumberByDefault()
          {
              var factory = new WorkerFactory();
              Worker worker = factory.Create("Nick");
              Assert.IsType<Plumber>(worker);
          }
      }
  }
  Build, Run Test: 结果Pass.
  相应的, 还有一个Assert.IsNotType<Type>(xx)方法.
  利用Assert.IsType<Type>(xx)的返回值, 它会返回Type(xx的)的这个实例, 添加个一test:
          [Fact]
          public void CreateProgrammerAndCastReturnedType()
          {
              var factory = new WorkerFactory();
              Worker worker = factory.Create("Nick", isProgrammer: true);
              Programmer programmer = Assert.IsType<Programmer>(worker);
              Assert.Equal("Nick", programmer.Name);
          }
  Build, Run Tests: 结果Pass.
  Assert针对父类:
  写这样一个test, 创建的是一个promgrammer, Assert的类型是它的父类Worker:
          [Fact]
          public void CreateProgrammer_AssertAssignableTypes()
          {
              var factory = new WorkerFactory();
              Worker worker = factory.Create("Nick", isProgrammer: true);
              Assert.IsType<Worker>(worker);
          }
  这个会Fail:
  这时就应该使用这个方法, Assert.IsAssignableFrom<祖先类>(xx):
          [Fact]
          public void CreateProgrammer_AssertAssignableTypes()
          {
              var factory = new WorkerFactory();
              Worker worker = factory.Create("Nick", isProgrammer: true);
              Assert.IsAssignableFrom<Worker>(worker);
          }
  Build, Run Tests: Pass.
  Assert针对对象的实例
  判断两个引用是否指向不同的实例 Assert.NotSame(a, b):
          [Fact]
          public void CreateSeperateInstances()
          {
              var factory = new WorkerFactory();
              var p1 = factory.Create("Nick");
              var p2 = factory.Create("Nick");
              Assert.NotSame(p1, p2);
          }
  由工厂创建的两个对象是不同的实例, 所以这个test会Pass.
  相应的还有个Assert.Same(a, b) 方法.
  Assert 异常
  为WorkFactory先添加一个异常处理:
  namespace Hospital
  {
      public class WorkerFactory
      {
          public Worker Create(string name, bool isProgrammer = false)
          {
              if (name == null)
              {
                  throw new ArgumentNullException(nameof(name));
              }
              if (isProgrammer)
              {
                  return new Programmer { Name = name };
              }
              return new Plumber { Name = name };
          }
      }
  }
  如果在test执行代码时抛出异常的话, 那么test会直接fail掉.
  所以应该使用Assert.Throws<ArgumentNullException>(...)方法来Assert是否抛出了特定类型的异常.
  添加一个test:
          [Fact]
          public void NotAllowNullName()
          {
              var factory = new WorkerFactory();
              // var p = factory.Create(null); // 这个会失败
              Assert.Throws<ArgumentNullException>(() => factory.Create(null));
          }
  注意不要直接运行会抛出异常的代码. 应该在Assert.Throws<ET>()的方法里添加lambda表达式来调用方法.
  这样的话就会pass.
  如果被测试代码没有抛出异常的话, 那么test会fail的. 把抛异常代码注释掉之后再Run:
  更具体的, 还可以指定参数的名称:
          [Fact]
          public void NotAllowNullName()
          {
              var factory = new WorkerFactory();
              // Assert.Throws<ArgumentNullException>(() => factory.Create(null));
              Assert.Throws<ArgumentNullException>("name", () => factory.Create(null));
          }
  这里就是说异常里应该有一个叫name的参数.
  Run: Pass.
  如果把"name"改成"isProgrammer", 那么这个test会fail:
  利用Assert.Throws<ET>()的返回结果, 其返回结果就是这个抛出的异常实例.
          [Fact]
          public void NotAllowNullNameAndUseReturnedException()
          {
              var factory = new WorkerFactory();
              ArgumentNullException ex = Assert.Throws<ArgumentNullException>(() => factory.Create(null));
              Assert.Equal("name", ex.ParamName);
          }
  Assert Events 是否发生(Raised)
  回到之前的Patient类, 添加如下代码:
          public void Sleep()
          {
              OnPatientSlept();
          }
          public event EventHandler<EventArgs> PatientSlept;
          protected virtual void OnPatientSlept()
          {
              PatientSlept?.Invoke(this, EventArgs.Empty);
          }
  然后回到PatientShould.cs添加test:
          [Fact]
          public void RaiseSleptEvent()
          {
              var p = new Patient();
              Assert.Raises<EventArgs>(
                  handler => p.PatientSlept += handler, 
                  handler => p.PatientSlept -= handler, 
                  () => p.Sleep());
          }
  Assert.Raises<T>()第一个参数是附加handler的Action, 第二个参数是分离handler的Action, 第三个Action是触发event的代码.
  Build, Run Test: Pass.
  如果注释掉Patient类里Sleep()方法内部那行代码, 那么test会fail:
  针对INotifyPropertyChanged的特殊Assert:
  修改Patient代码:
   View Code
  添加一个Test:
          [Fact]
          public void RaisePropertyChangedEvent()
          {
              var p = new Patient();
              Assert.PropertyChanged(p, "BloodSugar", () => p.HaveDinner());
          }
  针对INotifyPropertyChanged, 可以使用Assert.PropertyChanged(..) 这个专用的方法来断定PropertyChanged的Event是否被触发了。
  Build, Run Tests: Pass.
  到目前为止, 介绍的都是入门级的内容。


上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号