Friday, February 17, 2012

The difference between a Mock and a Stub

Many people have a lot of problems to understand the difference between a Mock and a Stub. Marting Fowler states that a Mock is about behaviour verification and a Stub is about state verification
From: http://martinfowler.com/articles/mocksArentStubs.html





  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
  • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
  • Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive. 


  • I am going to try to explain you in one simple example the difference...
    The classes involved:
    FileProcessor: The actual business logic, that we are trying to test, the Subject Under Test
    File: some file we are processing
    FileValidator: Performs some logic on the file to see if it contains errors
    FileMover: Moves the file to a specific location depending on the results returned by the FileValidator

    public class FileProcessor{
            private readonly IFileMover _FileMover;
            private readonly IFileValidator _FileValidator;

            //Constructor
            public FileProcessor(IFileMover fileMover, IFileValidator fileValidator){
                       IFileMover _FileMover = fileMover;
                       IFileValidator _FileValidator = fileValidator;
            }

            public void Process(File file){
                 ValidationResults result = _FileValidator.Validate(file);

                 if(result.IsValid){
                      _FileMover.Succes(file)
                 }else{
                      _FileMover.Error(file)
                  }
            }
    }

    public interface IFileMover{
           void Success(File file);
           void Error(File file);
    }

    public class ValidationResults{
                public virtual bool IsValid{
                     get;
                }
    }

    public interface IFileValidor{
           ValidationResults Validate(File file);
    }

    We need to create a dummy called DummyValidationResults

    public class DummyValidationResults: ValidationResults{
             public virtual bool IsValid{
                    get{ return false;}
             }
    }

    Now we create a Mock MockFileMover

    public class MockFileMover: IFileMover{

        public void Success(File file){
               this.SucessCalled++;
         }

        public void Error(File file){
             this.ErrorCalled++;
        }

        public int SuccesCalled{get; private set;}
        public int ErrorCalled{get; private set;}
    }

    We create a Stub named StubFileValidator

    public class StubFileValidator: IFileValidator{
         public ValidationResults Validate(File file){
            return new DummyValidationResult();
        }
    }


    now when we would like the test the Fileprocessor we can write:
        File aFile = new FakeFile();
        MockFileMover fileMover =  new MockFileMover()
        FileProcessor processor = new FileProcessor(new MockFileMover(), new StubFileValidator());
        processor.process(aFile);

        Assert.AreEqual(1,fileMover.ErrorWasCalled);
        Assert.AreEqual(0,fileMover.SuccessWasCalled);

    So what is the difference?
    The stub returns a predetermined answer what needs to happen and the path through the code dictates it will always be called. As you can see the methods of the mock are enclosed in decision logic in this case an if statement (this can as wel be a try catch switch or whatever), then we verify if the correct method on the mock has been called... so the mock is responsible for failing or succeeding the test...

    No comments:

    Post a Comment