C# 测试单个接口的不同具体实现?

C# 测试单个接口的不同具体实现?,c#,unit-testing,testing,mocking,tdd,C#,Unit Testing,Testing,Mocking,Tdd,我有以下代码: public interface IFoo { IResult ResolveTheProblem(IBar inputData); } public class FastFoo : IFoo { public IResult ResolveTheProblem(IBar inputData) { // Algorithm A - resolves the problem really fast } } public class

我有以下代码:

public interface IFoo
{
    IResult ResolveTheProblem(IBar inputData);
}

public class FastFoo : IFoo
{
    public IResult ResolveTheProblem(IBar inputData)
    {
        // Algorithm A - resolves the problem really fast
    }
}

public class SlowFoo : IFoo
{
    public IResult ResolveTheProblem(IBar inputData)
    {
        // Algorithm B - different algoritm, resolves the problem slow
    }
}
要测试的最重要的事情是每个算法的实现。 对于测试,我使用NUnit和NSubstitute。现在我有这样的测试:

    [Test]
    public void FooTest()
    {
        IFoo foo = Substitute.For<IFoo>();
        IBar bar = Substitute.For<IBar>();

        IResult result = foo.ResolveTheProblem(bar);

        Assert.IsNotNull(result);
    }
[测试]
公共空间
{
IFoo foo=替换.For();
IBar bar=替换为();
IResult result=foo.解决问题(bar);
Assert.IsNotNull(结果);
}
我的两个问题:

  • 那测试有必要吗?我不确定
  • 如何测试每个IFoo(FastFoo和SlowFoo)的实现

编辑:FastFoo和SlowFoo是两种完全不同的实现。两者的结果都是1到10之间的随机数

不,没有必要。为什么要测试替代实现? 您可以替换依赖项,如IBar。 您可以测试您的具体实现:

[Test]    
public void SlowFooTest()
{    
    IBar bar = Substitute.For<IBar>();
    // Setup bar expectations / canned responses as required
    var foo = new SlowFoo(bar);
    IResult result = foo.ResolveTheProblem(bar);
    // Validate result from concrete class:
    Assert.IsNotNull(result);
}

[Test]    
public void FastFooTest()
{    
    IBar bar = Substitute.For<IBar>();
    var foo = new FastFoo(bar);
    IResult result = foo.ResolveTheProblem(bar);
    Assert.IsNotNull(result);
}
[测试]
公共void SlowFooTest()
{    
IBar bar=替换为();
//根据需要设置栏期望值/固定响应
var foo=新的SlowFoo(巴);
IResult result=foo.解决问题(bar);
//验证混凝土等级的结果:
Assert.IsNotNull(结果);
}
[测试]
公共空间快步()
{    
IBar bar=替换为();
var foo=新的FastFoo(巴);
IResult result=foo.解决问题(bar);
Assert.IsNotNull(结果);
}

不,没有必要。为什么要测试替代实现? 您可以替换依赖项,如IBar。 您可以测试您的具体实现:

[Test]    
public void SlowFooTest()
{    
    IBar bar = Substitute.For<IBar>();
    // Setup bar expectations / canned responses as required
    var foo = new SlowFoo(bar);
    IResult result = foo.ResolveTheProblem(bar);
    // Validate result from concrete class:
    Assert.IsNotNull(result);
}

[Test]    
public void FastFooTest()
{    
    IBar bar = Substitute.For<IBar>();
    var foo = new FastFoo(bar);
    IResult result = foo.ResolveTheProblem(bar);
    Assert.IsNotNull(result);
}
[测试]
公共void SlowFooTest()
{    
IBar bar=替换为();
//根据需要设置栏期望值/固定响应
var foo=新的SlowFoo(巴);
IResult result=foo.解决问题(bar);
//验证混凝土等级的结果:
Assert.IsNotNull(结果);
}
[测试]
公共空间快步()
{    
IBar bar=替换为();
var foo=新的FastFoo(巴);
IResult result=foo.解决问题(bar);
Assert.IsNotNull(结果);
}
那测试有必要吗?我不确定

那项测试似乎没有任何作用。您似乎正在为正在测试的服务创建一个双重测试

如何测试每个IFoo(FastFoo和SlowFoo)的实现

对于FastFoo和SlowFoo来说,答案总是一样的,还是FastFoo以准确性换取速度

如果它们总是相同的,那么继承。用抽象的CreateFoo创建一个基本的
FooTest
。然后是两个具体的实现

如果它们不总是相同的,则再次使用模糊元素进行继承

abstract class AbstractFooTester {
    [Test]
    public void WhenBarIsSomethingThenResultIsSomethingElse() {
         var mockRandomNumberGenerator = createRandomNumberMock(5);
         var mockBar = Substitute.For<IBar>();
         // set up Bar
         ...
        var subject = createFoo(mockRandomNumberGenerator);
        IResult result = subject.ResolveTheProblem(bar);

        AssertResult(result, ...);
    }
    abstract Foo createFoo(RandomNumberGenertor g);
    RandomNumberGenertor createRandomNumberMock(Int i) { ... }
}

class TestFastFoo extends AbstractFooTester {
      Foo createFoo(RandomNumberGenertor g) { return new FastFoo(g); }
}

class TestSlowFoo extends AbstractFooTester {
      Foo createFoo(RandomNumberGenertor g) { return new SlowFoo(g); }
}
抽象类AbstractFooTester{
[测试]
当出现某些内容时,公共无效{
var mockRandomNumberGenerator=createRandomNumberMock(5);
var mockBar=Substitute.For();
//设立酒吧
...
var subject=createFoo(mockRandomNumberGenerator);
IResult结果=主题。解决问题(条形图);
资产结果(结果,…);
}
抽象Foo-createFoo(随机数发生器g);
RandomNumberGenerator createRandomNumberMock(inti){…}
}
类TestFastFoo扩展了AbstractFooTester{
Foo createFoo(RandomNumberGenerator g){返回新的FastFoo(g);}
}
类TestSlowFoo扩展了AbstractFooTester{
Foo createFoo(randomNumberGenerator g){返回新的SlowFoo(g);}
}
那测试有必要吗?我不确定

那项测试似乎没有任何作用。您似乎正在为正在测试的服务创建一个双重测试

如何测试每个IFoo(FastFoo和SlowFoo)的实现

对于FastFoo和SlowFoo来说,答案总是一样的,还是FastFoo以准确性换取速度

如果它们总是相同的,那么继承。用抽象的CreateFoo创建一个基本的
FooTest
。然后是两个具体的实现

如果它们不总是相同的,则再次使用模糊元素进行继承

abstract class AbstractFooTester {
    [Test]
    public void WhenBarIsSomethingThenResultIsSomethingElse() {
         var mockRandomNumberGenerator = createRandomNumberMock(5);
         var mockBar = Substitute.For<IBar>();
         // set up Bar
         ...
        var subject = createFoo(mockRandomNumberGenerator);
        IResult result = subject.ResolveTheProblem(bar);

        AssertResult(result, ...);
    }
    abstract Foo createFoo(RandomNumberGenertor g);
    RandomNumberGenertor createRandomNumberMock(Int i) { ... }
}

class TestFastFoo extends AbstractFooTester {
      Foo createFoo(RandomNumberGenertor g) { return new FastFoo(g); }
}

class TestSlowFoo extends AbstractFooTester {
      Foo createFoo(RandomNumberGenertor g) { return new SlowFoo(g); }
}
抽象类AbstractFooTester{
[测试]
当出现某些内容时,公共无效{
var mockRandomNumberGenerator=createRandomNumberMock(5);
var mockBar=Substitute.For();
//设立酒吧
...
var subject=createFoo(mockRandomNumberGenerator);
IResult结果=主题。解决问题(条形图);
资产结果(结果,…);
}
抽象Foo-createFoo(随机数发生器g);
RandomNumberGenerator createRandomNumberMock(inti){…}
}
类TestFastFoo扩展了AbstractFooTester{
Foo createFoo(RandomNumberGenerator g){返回新的FastFoo(g);}
}
类TestSlowFoo扩展了AbstractFooTester{
Foo createFoo(randomNumberGenerator g){返回新的SlowFoo(g);}
}

我不确定我是否理解。你是说我不应该测试具体类的内容吗?@user5883596不,他是说你只需要测试具体类,而不需要测试接口。您使用接口的替代物来帮助您获得具体的类来执行您想要测试的操作,因此,您可以让IBar的替代者根据您试图针对具体类型(如
SlowFoo
@forsvarir)执行的测试的要求返回一个已知的数字/集合,谢谢您的澄清。我认为我不应该在测试中创建具体类的对象。我认为我不应该做
varfoo=newfastfoo(bar)我不确定我是否理解。你是说我不应该测试具体类的内容吗?@user5883596不,他是说你只需要测试具体类,而不需要测试接口。您可以使用接口的替代品来帮助您获得具体的类来执行您想要测试的操作,因此您可以使用
IBar的替代品