3

Can I replace (or override) a class definition with one of my own implementation?

Explanation:

  • I have a class with a System.Random instance, and I am trying to test it without modifying its original code...
  • So I am planning to replace Random class with one of my own implementation, that allows controlling generated sequence.. Please see this question.

`

class foo
{
    Random r=new Random();
    double bar()
    {
         double ans=r.NextDouble();
         .....// evaluate ans
         return ans;
    }
}

`

What are the possible ways that I can replace implementation of Random class with another one without changing (or with minimum changes) the original code file??

Edit:
One solution is to inherit Random class and modify it... but that requires changing each Random instance with the inherited one... I do not want to modify the code, because I am just testing it!!
Edit 2:
Can I say in C#: "Each Random class in this file is MyNamespace.Random not System.Random" ??

7
  • Can you clarify? Do you want to just replace some if it's members? Do you want to extend it to add new ones? Commented Nov 18, 2010 at 21:16
  • 1
    Sounds like you're after creating mocks, could that be? Commented Nov 18, 2010 at 21:17
  • @Lucero +1, I was thinking the same thing Commented Nov 18, 2010 at 21:18
  • I am concerned to add a function setNextSequence(double []) to this Random class, so that before calling NextDouble() I set the random numbers to be generated using this function... But I do not want to edit the original code as I am just testing it..!! Commented Nov 18, 2010 at 21:19
  • 1
    Wouldn't be great if we could force the CLR types to adhere to interfaces that we specify based on existing methods only. Such that we could force a IRandom { double NextDouble(); } interface into the System.Random type and abstract it in our code. Commented Nov 18, 2010 at 21:36

6 Answers 6

5

EDIT: As ChaosPandion points out, to test the logic in the method it would be better to take a double parameter i.e. double bar(double input) { ... }, but if you have a reason to need to inject your own source of randoms, you could use one of these approaches:

You could modify bar to take a Func<double> to obtain values from:

double bar(Func<double> source)
{
    double ans = source();
    //evaluate ans
    return ans;
}

Then you can inject your own implementation for testing, and in the main program use:

Random r = new Random();
double ans = bar(r.NextDouble);

Alternatively you could create your own IRandom interface and then implement a wrapper around the real Random class and use mocks for testing:

interface IRandom
{
    double Next();
}

public class RandomWrapper : IRandom
{
    private Random r = new Random();
    public double Next()
    {
        return this.r.NextDouble();
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

I up-voted you but I just need to ask, why not take a double as a parameter?
3

You can do this and no code changes to the source are necessary.

You can use reflection to inject a mock or derived instance.

Since System.Random is not sealed, your best bet here is to derive a new class, and then you only need to override the desired methods.

I'm assuming that you are using some type of unit testing framework, so the example below is for that.

In your unit test file, do this:

class MyRandom : System.Random 
{
     public override double NextDouble()
     {     
          // return your fake random double here.
     }
}


class TestFixture 
{
     public void UnitTest()
     {
          // Create the unit under test
          foo unit = new foo();

          // use reflection to inject a mock instance
          typeof(foo)
             .GetField("r", BindingFlags.Instance | BindingFlags.NonPublic)
             .SetValue(unit, new MyRandom());

          // ACT: call method
          var result = foo.bar();

          // examine results
      }
 }

4 Comments

Wow.. that is nearly what I need... I wonder if this will work on private fields??
Yeah, no problem. It depends on how you specify the BindingFlags.
Will this work everywhere - i.e if I create a class instance of something in the .NET framework and it uses new Random() it will get an instance of MyRandom?
Depends on how it is used. If a class's field is set to an instance of new Random(), that can be replaced via reflection. If a new Random() is created within a method, that cannot be replaced.
2

I believe that you can replace the implementation of a class like Random using tools such as JustMock or TypeMock.

However, without restructuring your original code to use dependency injection (or otherwise insert a layer of abstraction) you won't be able to do what you're asking using plain C#. That said, restructuring your code to get rid of hard dependencies makes the code cleaner and simpler, so I would say that it should be the preferred route unless you're really unable to perform the necessary restructuring.

Comments

1

You could derive a class from System.Random and override its methods.

class PseudoRandom : System.Random
{
    public override int Next () {...}
    public override int Next (int maxValue) {...}
    public override int Next (int minValue, int maxValue) {...}
    public override void NextBytes (byte [] buffer) {...}
    public override double NextDouble () {...}
}

Use this class to instantiate from Main.

Random random = new PseudoRandom ();

If you need to determine later on whether you are using the system class or your own derived version, you can check that using the "is" operator. (Probably not the best design, but it's quick and easy)

// We need to see which class we're working with
if (random is PseudoRandom)
{
    // Using our custom class
}
else
{
    // Using default System.Random class
}

2 Comments

Good idea.. but Can I say in C#: "Each Random class in this file is MyNamespace.Random not System.Random" ??
Yes, check with the is operator. Updated response.
-1

Take a look into using Dependency Injection. It is designed for exactly this circumstance. There are several different DI/IoC frameworks for c#.

Unity and Ninject are both good but there are many others.

Comments

-1

You need to add a layer of abstraction.

Create an interface that defines the contract you need your Random classes to support.

Create implementations of that interface, one of which should utilize the original Random class, the other would be your "random" implementation.

Provide the correct implementation when and where needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.