#StackBounty: #angular #unit-testing #angular-material #mocking #jestjs Angular Jest Testing a component that opens a MatDialog – open …

Bounty: 100

Similar to this question, but it doesn’t provide an answer that works for me.

I have a simple component that has a method that opens a dialog:

  enterGiveaway() {
    this.dialog.open(SpendTicketsDialogComponent, {
      width: '370px',
      height: '600px'
    });
  }

For now I just want to test that calling that method results in the dialog being opened.

The test fails with this error:

  expect(spy).toBeCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

with this code:

    import {async, ComponentFixture, TestBed} from '@angular/core/testing';
    
    import {GiveawayItemComponent} from './giveaway-item.component';
    import {giveawaysMock} from '../../../../../mocks/giveaways.mock';
    import {MaterialModule} from '../../material.module';
    import {getTranslocoModule} from '../../../transloco-testing.module';
    import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
    import {MatDialog} from '@angular/material/dialog';
    import {EMPTY} from 'rxjs';
    import {SpendTicketsDialogComponent} from '../dialogs/tickets-dialog/spend-tickets-dialog.component';
    import {NumberFormatter} from '../../filters/numberFormatter/numberFormatter.filter';
    import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
    import {BrowserModule} from '@angular/platform-browser';
    
    describe('GiveawayItemComponent', () => {
      let component: GiveawayItemComponent;
      let fixture: ComponentFixture<GiveawayItemComponent>;
      let dialog: any;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [
            GiveawayItemComponent,
            SpendTicketsDialogComponent,
            NumberFormatter
          ],
          imports: [
            MaterialModule,
            BrowserAnimationsModule,
            getTranslocoModule({})
          ],
          schemas: [CUSTOM_ELEMENTS_SCHEMA]
        })
          .overrideModule(BrowserModule, {
            set: {entryComponents: [SpendTicketsDialogComponent]}
          })
          .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(GiveawayItemComponent);
        component = fixture.componentInstance;
        component.giveaway = giveawaysMock[0];
        component.numberOfChances = 100;
        dialog = TestBed.inject(MatDialog);
        fixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    
      describe('enterGiveaway', () => {
        it('should open the spend tickets dialog', async(() => {
          component.enterGiveaway();
          fixture.detectChanges();
          const spy = spyOn(dialog, 'open').and.returnValue({
            afterClosed: () => EMPTY
          });
    
          expect(spy).toBeCalledTimes(1);
        }));
      });
    });

I understand of course, that MatDialog is not referencing the actual SpendTicketsDialogComponent which is the one that is opened. So I tried providing a mock object for the dialog:

    import {async, ComponentFixture, TestBed} from '@angular/core/testing';
    
    import {GiveawayItemComponent} from './giveaway-item.component';
    import {giveawaysMock} from '../../../../../mocks/giveaways.mock';
    import {MaterialModule} from '../../material.module';
    import {getTranslocoModule} from '../../../transloco-testing.module';
    import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
    import {MatDialog} from '@angular/material/dialog';
    import {of} from 'rxjs';
    import {SpendTicketsDialogComponent} from '../dialogs/tickets-dialog/spend-tickets-dialog.component';
    import {NumberFormatter} from '../../filters/numberFormatter/numberFormatter.filter';
    import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
    import {BrowserModule} from '@angular/platform-browser';
    
    class dialogMock {
      open() {
        return {
          afterClosed: () => of({})
        };
      }
    }
    
    describe('GiveawayItemComponent', () => {
      let component: GiveawayItemComponent;
      let fixture: ComponentFixture<GiveawayItemComponent>;
      let dialog: any;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [
            GiveawayItemComponent,
            SpendTicketsDialogComponent,
            NumberFormatter
          ],
          imports: [
            MaterialModule,
            BrowserAnimationsModule,
            getTranslocoModule({})
          ],
          providers: [{provide: MatDialog, useValue: dialogMock}],
          schemas: [CUSTOM_ELEMENTS_SCHEMA]
        })
          .overrideModule(BrowserModule, {
            set: {entryComponents: [SpendTicketsDialogComponent]}
          })
          .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(GiveawayItemComponent);
        component = fixture.componentInstance;
        component.giveaway = giveawaysMock[0];
        component.numberOfChances = 100;
        dialog = TestBed.inject(MatDialog);
        fixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    
      describe('enterGiveaway', () => {
        it('should open the spend tickets dialog', async(() => {
          component.enterGiveaway();
          fixture.detectChanges();
          const spy = spyOn(dialog, 'open').and.callThrough();
    
          expect(spy).toBeCalledTimes(1);
        }));
      });
    });

but this throws the error this.dialog.open is not a function.

I actually don’t think either solution is correct, because I need to check that calling enterGiveaway opens the SpendTicketsDialog.

So how can I verify that?


Get this bounty!!!

#StackBounty: #unit-testing #mocking #racket #rackunit Monkey-patching with mock objects in Racket

Bounty: 50

Racket has some neat testing libraries, including Rackunit and Mock. I was wondering whether there’s a standard way to monkey-patch internal calls in the function being tested (e.g. similar to python’s mock.patch), either using these or other libraries.

That is, suppose we’re testing this function:

(define (compute x)
  (+ 1 (consult-api x))

We want to check that compute yields the expected results with different return values of consult-api, which we could validate using Rackunit checks. We’d like to replace consult-api with a mock for the purposes of the test.

The mock library suggests adding keyword arguments to the function being tested so that we can supply such mocks to it for use during testing, but I was hoping for a way that would not involve modifying the original function.

It seems like what we are looking for here could be accomplished with some kind of macro, by rewriting instances of consult-api as mock-consult-api, the latter of which would be a mock defined in the test. I’m not familiar enough with Racket macros to know whether it’s possible to define such a macro in a test and have it apply to the compilation of the module being tested.

How should one accomplish this in the best/Rackety-est way?


Get this bounty!!!

#StackBounty: #python #django #python-3.x #mocking #python-unittest Why does this assert_has_calls with the usage of ANY fail in python…

Bounty: 50

It looks like the version of the mock is 3.0.5 in both Python 2.7.15 and 3.7.5 I am testing in.

with patch('a.models.BManager.methodC',autospec=True) as method_mock:
    do something

    expected_calls = [
        call(ANY, param_a=some int value, param_c=some datetime value, etc..),
        call(ANY, param_a=some int value, param_c=some datetime value, etc..)
    ]

    method_mock.assert_has_calls(expected_calls, any_order=True)

This succeeds in Python 2.

However, in Python 3, I get (a few new lines inserted for better formatting)

AssertionError: 'methodC' does not contain all of 

(('', <BoundArguments (self=<ANY>, param_a=1, param_b=2, param_c=datetime.datetime(2020, 1, 29, 11, 47, 11))>), ('', <BoundArguments (self=<ANY>, param_a=1, param_b=3, param_c=datetime.datetime(2020, 1, 30, 3, 47, 11))>))

in its call list, found

[('', <BoundArguments (self=<a.models.BManager object at 0x7fc95ff66fd0>, param_a=1, param_b=2, param_c=datetime.datetime(2020, 1, 29, 11, 47, 11))>), ('', <BoundArguments (self=<a.models.BManager object at 0x7fc95ff66fd0>, param_a=1, param_b=3, param_c=datetime.datetime(2020, 1, 30, 3, 47, 11))>)]

instead

The code that’s being run is:

ModelClassOfBManager.objects.methodC(param_a=1, etc)

Can anyone help me why this, which succeeds in Python 2, fail in Python 3? The expected calls and actual calls are exactly the same except the value for ‘self’ which I used ANY.

Additional Info: The test passes also in python 3 if I remove “autospec=True” from mocking and remove “ANY” from the call(). So I have a hunch that it is related to how ANY and ‘self’ work in Python 3.


Get this bounty!!!

#StackBounty: #javascript #node.js #mocking #jestjs Jest method-invocation count is wrong?

Bounty: 50

Consider code –

// utils.js
export const foo = async (a, b) => {
   // do something
   bar(a)
}

export const bar = async (a) => {
   // do something
}

// utils.spec.js
const utils = require('./utils');

const barSpy = jest.spyOn(utils, 'bar');
const result = await utils.foo('a', 'b');

expect(barSpy).toHaveBeenCalledTimes(1);

The test is failing –

Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)

Expected number of calls: 1
Received number of calls: 0

I read https://medium.com/@DavideRama/mock-spy-exported-functions-within-a-single-module-in-jest-cdf2b61af642 and https://github.com/facebook/jest/issues/936 but could not solve this with multiple permutations.

Do you see any issue with this?


Get this bounty!!!

#StackBounty: #python #unit-testing #mocking Mocking attribute to change each time it is accessed

Bounty: 50

Here is the function I want to test:

def send_something():
    conn = lib.conn.SSH1
    conn.open()
    conn.send('lsn')
    if 'home' not in conn.recbuf:
        return lib.FAIL

    conn.send('whoamin')
    if USER not in conn.recbuf:
        return lib.FAIL
    return lib.PASS

Every time I call conn.send() the output of the call is stored in conn.recbuf. To test this I need conn.recbuf to be different each time it is called. (I know I could just change conn.recbuf to be a string that contains both home and USER but that won’t work for more complicated functions)

Here is what I have come up with so far in my test:

@mock.patch.object(demo_sequence.lib, 'conn')
def test_send_something(mock_conn):
    mock_conn.SSH1.recbuf = 'home'
    assert demo_sequence.lib.PASS == demo_sequence.send_something()
    mock_conn.SSH1.send.assert_any_call('lsn')
    mock_conn.SSH1.send.assert_any_call('whoamin')

Obviously this fails because conn.recbuf is only ‘home’ and does not contain USER.

I need something like conn.recbuf.side_effect = [‘home’, USER] but will work when just referencing recbuf and not calling it.


Get this bounty!!!

#StackBounty: #go #mocking #gomock resolving imported package collision for mockgen

Bounty: 50

I have a package collision where I get the following error:

mockgen -package=mocks -source=myproto.pb.go -destination=mocks/my_mocks.go
imported package collision: "foo" imported twice

I see one import that is obvious:
import foo "blah/blah/foo"

But I don’t know where to start tracking down the duplicate import (nor where it is coming from). It seems strange to me that this is an issue as I am importing myproto.pb.go just fine, so I’m wondering if there is really an issue w/duplicate imports. Also, GoLand isn’t showing any issues.

I’m hoping someone can point me in the direction of getting more information about where the duplicate import is coming form, checking if there is some issue and/or working around the issue.


Get this bounty!!!