function assertChanges(subject, prop, msg) {
  if (msg) flag(this, 'message', msg);
  let fn = flag(this, 'object'),
    flagMsg = flag(this, 'message'),
    ssfi = flag(this, 'ssfi');
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');

  let initial;
  if (!prop) {
    new Assertion(subject, flagMsg, ssfi, true).is.a('function');
    initial = subject();
  } else {
    new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop);
    initial = subject[prop];
  }

  fn();

  let final = prop === undefined || prop === null ? subject() : subject[prop];
  let msgObj = prop === undefined || prop === null ? initial : '.' + prop;

  // This gets flagged because of the .by(delta) assertion
  flag(this, 'deltaMsgObj', msgObj);
  flag(this, 'initialDeltaValue', initial);
  flag(this, 'finalDeltaValue', final);
  flag(this, 'deltaBehavior', 'change');
  flag(this, 'realDelta', final !== initial);

  this.assert(
    initial !== final,
    'expected ' + msgObj + ' to change',
    'expected ' + msgObj + ' to not change'
  );
}
### .change(subject[, prop[, msg]])

When one argument is provided, `.change` asserts that the given function
`subject` returns a different value when it's invoked before the target
function compared to when it's invoked afterward. However, it's often best
to assert that `subject` is equal to its expected value.

    var dots = ''
    , addDot = function () { dots += '.'; }
    , getDots = function () { return dots; };

    // Recommended
    expect(getDots()).to.equal('');
    addDot();
    expect(getDots()).to.equal('.');

    // Not recommended
    expect(addDot).to.change(getDots);

When two arguments are provided, `.change` asserts that the value of the
given object `subject`'s `prop` property is different before invoking the
target function compared to afterward.

    var myObj = {dots: ''}
    , addDot = function () { myObj.dots += '.'; };

    // Recommended
    expect(myObj).to.have.property('dots', '');
    addDot();
    expect(myObj).to.have.property('dots', '.');

    // Not recommended
    expect(addDot).to.change(myObj, 'dots');

Strict (`===`) equality is used to compare before and after values.

Add `.not` earlier in the chain to negate `.change`.

    var dots = ''
    , noop = function () {}
    , getDots = function () { return dots; };

    expect(noop).to.not.change(getDots);

    var myObj = {dots: ''}
    , noop = function () {};

    expect(noop).to.not.change(myObj, 'dots');

`.change` accepts an optional `msg` argument which is a custom error
message to show when the assertion fails. The message can also be given as
the second argument to `expect`. When not providing two arguments, always
use the second form.

    var myObj = {dots: ''}
    , addDot = function () { myObj.dots += '.'; };

    expect(addDot).to.not.change(myObj, 'dots', 'nooo why fail??');

    var dots = ''
    , addDot = function () { dots += '.'; }
    , getDots = function () { return dots; };

    expect(addDot, 'nooo why fail??').to.not.change(getDots);

`.change` also causes all `.by` assertions that follow in the chain to
assert how much a numeric subject was increased or decreased by. However,
it's dangerous to use `.change.by`. The problem is that it creates
uncertain expectations by asserting that the subject either increases by
the given delta, or that it decreases by the given delta. It's often best
to identify the exact output that's expected, and then write an assertion
that only accepts that exact output.

    var myObj = {val: 1}
    , addTwo = function () { myObj.val += 2; }
    , subtractTwo = function () { myObj.val -= 2; };

    expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended
    expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended

    expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended
    expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended

The alias `.changes` can be used interchangeably with `.change`.

@name change
@alias changes
@param {string} subject
@param {string} prop name _optional_
@param {string} msg _optional_
@namespace BDD
@public