Jass Huang
Jass Huang

Reputation: 51

Questions about unit test

Recently, I am learning unit test and try to use this skill in my project. However, I have some question about how to test following code.

 public class Class1
{
    private Timer _timer = new Timer();

    public Class1()
    {
        _timer.Interval = 1000;
        _timer.Elapsed += _timer_Elapsed;
    }

    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //some works
    }

    public void start()
    {
        _timer.Start();
        //some works

    }
    public void stop()
    {
        _timer.Stop();
        //some works
    }
}

I truly don't know how to test this class without breaking its encapsulation.

Should I expose '_timer_Elapsed' method? Evan if do so, next question comes to how to test method 'start' and 'stop'. Should I use stub object to substitute the Timer in order to test this class? if that, this class will be too complex because I need to make an interface and make a class which encapsulates Timer and implement the interface above.

public interface IEncal
{
    double Interval { get; set; }
    event ElapsedEventHandler Elapsed;
    void Stop();
    void Start();
}
public class MyClass : IEncal
{
    Timer timer = new Timer();
    public double Interval { get { return timer.Interval; } set { timer.Interval = value; } }

    public event ElapsedEventHandler Elapsed
    {
        add { timer.Elapsed += value; }
        remove { timer.Elapsed -= value; }
    }

    public void Start()
    {
        timer.Start();
    }

    public void Stop()
    {
        timer.Stop();
    }
}
public class Class1
{
    private IEncal _timer;

    public Class1(IEncal timer)
    {
        _timer = timer;
        _timer.Interval = 1000;
        _timer.Elapsed += _timer_Elapsed;
    }

    public void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //some works
    }

    public void start()
    {
        _timer.Start();
        //some works
    }
    public void stop()
    {
        _timer.Stop();
        //some works
    }
}

Is there any better way to test this class?


The following is the real code I use. I've written the unit test for ISender class and IInfoProducer class. Since it's my first time to use unit test, I would like to think about each class for learning.

Back to the question, this class is basically a Timer class. When elapsing , it sends a info. So how should I test this timing sending process?

public class InfomationSender
{
    private readonly Timer _timer = new Timer();
    private readonly ISender _sender;
    private readonly IInfoProducer _producer;

    public InfomationSender(ISender sender, IInfoProducer producer)
    {
        _sender = sender;
        _producer = producer;
        _timer.Interval = 1000;
        _timer.Elapsed += _timer_Elapsed;
    }

    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        var info = _producer.getInfo();
        _sender.send(info);

    }

    public void start()
    {
        _timer.Start();

    }
    public void stop()
    {
        _timer.Stop();
        _sender.Dispose();
    }
}

Upvotes: 2

Views: 102

Answers (1)

Fabio
Fabio

Reputation: 32445

You should be able test the class without mocking. Less mocking more valuable tests are. But you didn't provide information about what your code is doing in // some works areas. Because this is what you want to test, timer is just implementation details.

For testing "some works" class should provide some public access to the result of "some works" or result will be "exposed" through injected dependency (repository, logger etc)

Assume class will execute "some work" every second and update Result property after Stop method is called.

public class LiveCalculator
{
    private readonly Timer _timer;
    private List<int> _allValues
    private int _lastSum;

    public int LastSum => _lastSum;

    public LiveCalculator()
    {
        _allValues = new List<int>();
        _timer = new Timer { Interval = 1000 };
        _timer.Elapsed += _timer_Elapsed;
    }

    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _allValues.Add(42);
    }

    public void start()
    {
        _timer.Start();            
    }

    public void stop()
    {
        _timer.Stop();
        _lastResult = _allValues.Sum();
    }
}

Tests

[Fact]
public async Task AfterFiveSeconds_LastResultEquals210()
{
    var calculator = new LiveCalculator();

    calculator.Start();        
    await Task.Delay(5100);
    calculator.Stop();

    calculator.LastResult.Should().Be(210);
}

Upvotes: 1

Related Questions