I would like to test whether a particular function is called from the function I'm testing however both of these functions are within the es6 class I am testing.
Setup:
// MyClass.js
export default class MyClass {
constructor () { ... }
foo() {
...
bar()
}
bar() {
...
}
}
So I am testing foo() but as part of my test I want to ensure that bar() is called. I can see how I can do this if bar() was an external dependency as I could just mock that but as it's part of the class I am testing I can't mock the entire class otherwise I wouldn't be calling a concrete implementation in my test.
I was hoping this would've done the trick (as per https://facebook.github.io/jest/docs/en/es6-class-mocks.html) but to no avail:
// MyClass.spec.js
jest.unmock('./MyClass')
import MyClass from './MyClass'
...
test('my test', () => {
var mockBar = jest.fn()
MyClass.bar = mockBar
var myClass = new MyClass()
myClass.foo()
expect(mockBar).toHaveBeenCalled()
})
I also tried mocking the method on the instantiated version of MyClass (i.e. myClass.bar = mockBar) but neither gave the desired results.
Is this mocking structure possible with jest?
When testing specific method of ES6 class (not class instance) you should mock not the property of the class, but property of this class prototype.
jest.unmock('./MyClass')
import MyClass from './MyClass'
...
test('my test', () => {
var mockBar = jest.fn()
MyClass.prototype.bar = mockBar // here's the difference
var myClass = new MyClass()
myClass.foo()
expect(mockBar).toHaveBeenCalled()
})
This is because ES6 classes is just sugar over plain Javascript prototype model, and
class MyClass {
bar() {}
}
is equivalent not to
var MyClass = function () {
MyClass.bar = function bar() {};
return MyClass;
}();
but to
var MyClass = function () {
MyClass.prototype.bar = function bar() {};
return MyClass;
}();
Related
This is the class that I want to test.
open class Foo(bar :Bar){
fun someMethod() = bar.anotherMethod()
}
And I have a builder class to get Foo mock instance since Mockito cant mock constructor arguments.
open class FooBuilder{
fun makeFoo(bar:Bar) = Foo(bar)
}
Here is my approach to make the mock Objects and verify.
var fooBuilderMock = mock(FooBuilder::class)
var barMock = mock(Bar::class)
var fooMock = mock(Foo::class)
Mockito.`when`(fooBuilderMock.makeFoo(barMock)).thenReturn(fooMock)
fooMock.someMethod()
Mockito.verify(barMock, Mockito.times(1)).anotherMethod()
I am getting a null pointer exception on barMock object.
Don't use the Builder, there is no need for it. Additionally, don't mock the class that you are trying to test. If you do it, your test makes no sense.
class FooTest {
private val barMock = mock(Bar::class)
private lateinit var foo: Foo
#BeforeEach
fun setUp() {
MockitoAnnotations.initMocks(this)
foo = Foo(barMock)
}
#Test
fun `Your test name`() {
// Arrange
Mockito.`when`(barMock.anotherMethod()).thenReturn(// whatever it should return)
// Act
fooMock.someMethod()
// Assert
Mockito.verify(barMock, Mockito.times(1)).anotherMethod()
}
}
As a side note consider taking a look at mockk and using it instead of Mockito. It is implemented in kotlin and thus supports it since day 1. With it, your test would look similar but follow more the kotlin "style":
class FooTest {
#MockK
private lateinit var barMock = mock(Bar::class)
private lateinit var foo: Foo
#BeforeEach
fun setUp() {
MockitoAnnotations.initMocks(this)
foo = Foo(barMock)
}
#Test
fun `Your test name`() {
// Arrange
every { barMock.anotherMethod() } returns //whatever it should return
// Act
foo.someMethod()
// Assert
verify(exactly = 1) { barMock.anotherMethod() }
}
}
I have a controller class with a method something() which makes calls to two different methods of the same class and merge the result of two calls.
class Controller{
...
public UDC doSomething(){
CompletableFuture<UDC> feature1 = CompletableFuture.supplyAsync(()-> {this.doOther()}).exceptionally(ex -> {return new SomeException();});
CompletableFuture<UDC> feature2 = CompletableFuture.supplyAsync(()-> {this.doSomeOther()}).exceptionally(ex -> {return new SomeException();});
...
return feature1.combine(feature2).get();
}
...
}
I don't think you should use Mockito to mock CompletableFuture here, any of them...
In the test, treat the Controller's doSomething functionality as a black box that given some input returns UDC.
Now, it's possible that doOther and/or doSomeOther call some external code that should be mocked. In this case the Controller looks probably something like this:
class Controller {
private final SomeExternalDependency dependency1;
public Controller(SomeExternalDependency dependency1) {
this.dependency1 = dependency1;
}
private UDC doOther() {
...
dependency1.foo();
...
}
private UDC toSomeOther() {
...
dependency1.bar();
...
}
}
In this case in the test you can mock out the dependency1 with mockito as usual:
class MyTest {
#Test
public void doSomething() {
SomeExternalDependency dep = Mockito.mock(SomeExternalDependency.class);
// specify the expectations
Controller controller = new Controller(dep);
controller.doSomething();
}
}
Is there a way to create a jasmine unit test for an abstract component?
doing
const fixture = TestBed.createComponent(MyAbstractComponent);
says, "cannot assign an abstract constructor type to a non-abstract constructor type"
I tried some searching but nothing comes up.
You can create a simple class in your test file which extends from abstract class (do not forget to mock abstract methods), than just test its non abstract methods. Let's say we have MyAbstractClass:
export abstract class MyAbstractClass {
sum(a: number, b: number): number {
return a + b;
}
abstract calc1(): void;
abstract calc2(): void;
}
and then in spec file we can just create a new derived class:
class MyClass extends MyAbstractClass {
// just mock any abstract method
calc1(): void {
return;
}
calc2(): void {
return;
}
}
So now we can write tests for non-abstract methods:
describe('MyAbstractClass', () => {
let myClass: MyClass;
beforeEach(() => {
myClass = new MyClass();
});
it('sum two args', () => {
const a = 1, b = 2;
const sum = myClass.sum(a, b);
expect(sum).toBe(3);
});
});
Also created a stackblitz example of this test example.
Here is what I did to test an angular pipe SafePipe that was using a built in abstract class DomSanitizer.
// 1. Import the pipe/component to be tested
import { SafePipe } from './safe.pipe';
// 2. Import the abstract class
import { DomSanitizer } from '#angular/platform-browser';
// 3. Important step - create a mock class which extends
// from the base class imported above and add implement
// the mock methods
class MockDomSanitizer extends DomSanitizer {
sanitize(): string{
return 'ANY';
}
bypassSecurityTrustHtml(): string{
return 'ANY'
}
bypassSecurityTrustStyle(): string{
return 'ANY'
}
bypassSecurityTrustScript(): string{
return 'ANY'
}
bypassSecurityTrustUrl(): string{
return 'ANY'
}
bypassSecurityTrustResourceUrl(): string{
return 'ANY'
}
}
describe('SafePipe', () => {
it('should return an HTML string', () => {
// 4. create an instance of pipe class and inject the mocked class above
let safePipe = new SafePipe(new MockDomSanitizer());
// 5. Add your asserions as ususal
expect(safePipe.transform(null, 'html')).toBeTruthy();
expect(safePipe.transform(null, 'style')).toBeTruthy();
expect(safePipe.transform(null, 'script')).toBeTruthy();
expect(safePipe.transform(null, 'url')).toBeTruthy();
expect(safePipe.transform(null, 'resourceUrl')).toBeTruthy();
expect(safePipe.transform(null, 'anything')).toContain('anything');
});
});
Let's say I have a dagger 2 module as follows,
#Module
interface Creator {
MyClass create();
}
and I am using it to create an instance of MyClass
class Instantiator {
void doSomething(){
MyClass clazz = DaggerCreator.create().create();
// do things with clazz
}
}
It seems to me that I cannot effectively test the doSomething method in Instantiator because I cannot provide a mock for MyClass.
Am I wrong? If not are we supposed to use Dagger instantiation sparingly?
You are correct in saying that it is hard to test use of a Component injector, since this is a static method. But harder than what? Here is the same method using instantiation:
class Instantiator {
void doSomething(){
MyClass clazz = new MyClass();
// do things with clazz
}
}
still hard to test, right?
The point is to use as few Component (injectors) as possible and to pass in dependencies in the constructor for your objects. Dagger 2 makes resolving the dependencies in the constructor easy. This thereby makes testing easy since you can pass in mock object in a constructor.
Let's refactor the code you wrote to be testable. Assume that MyClass contains a single method, fireLazers() that you want to test is being invoked inside Instantiator's doSomething() method:
public class DoerOfSomething {
private final MyClass myClass;
#Inject
public DoerOfSomething(MyClass myClazz) {
this.myClass = myClazz;
}
public void doSomething() {
myClass.fireLazers();
}
}
Now you can write a test like this using a mock object:
public void DoerOfSomethingTest {
//mocks
MyClass mockMyClass;
//system under test
DoerOfSomething doerOfSomething;
#Before
public void setUp() {
mockMyClass = Mockito.mock(MyClass.class);
}
#Test
public void whenDoSomething_thenInteractsWithMyClass() {
//arrange
doerOfSomething = new DoerOfSomething(mockMyClass);
//act
doerOfSomething.doSomething();
//assert
verify(mockMyClass).fireLazers();
}
}
Of course, you will now need to inject DoerOfSomething into the top level class where you are injecting, but now you can be certain that the object you are injecting is functioning as expected because it is testable. Your code for using Dagger looks a bit unusual but I'll use your idioms for the sake of parity between the question and the answer.
class Instantiator {
private final DoerOfSomething doerOfSomething;
Instantiator() {
doerOfSomething = DaggerCreator.create().create();
}
void doSomething() {
doerOfSomething.doSomething();
}
}
How can I do this in Moq?
Foo bar = new Foo();
Fake(bar.PrivateGetter).Return('whatever value')
It seems I can only find how to mock an object that was created via the framework. I want to mock just a single method/property on a concrete object I've created.
In TypeMock, I would just do Isolate.WhenCalled(bar.PrivateGetter).Returns('whatever value').
Any ideas?
You should use Moq to create your Mock object and set CallBase property to true to use the object behavior.
From the Moq documentation:
CallBase is defined as “Invoke base class implementation if no expectation overrides the member. This is called “Partial Mock”. It allows to mock certain part of a class without having to mock everything.
Sample code:
[Test]
public void FailintgTest()
{
var mock = new Moq.Mock<MyClass>();
mock.Setup(m => m.Number).Returns(4);
var testObject = mock.Object;
Assert.That(testObject.Number, Is.EqualTo(4));
Assert.That(testObject.Name, Is.EqualTo("MyClass"));
}
[Test]
public void OKTest()
{
var mock = new Moq.Mock<MyClass>();
mock.Setup(m => m.Number).Returns(4);
mock.CallBase = true;
var testObject = mock.Object;
Assert.That(testObject.Number, Is.EqualTo(4));
Assert.That(testObject.Name, Is.EqualTo("MyClass"));
}
public class MyClass
{
public virtual string Name { get { return "MyClass"; } }
public virtual int Number { get { return 2; } }
}
Only TypeMock Isolator (and perhaps Moles) can perform these stunts. Normal dynamic mock libraries can only mock virtual and abstract members.
Moles can also replace private methods as long as the types on the signature are visible. So in this case, it would look like this:
MFoo bar = new MFoo { // instantiate the mole of 'Foo'
PrivateGetterGet = () => "whatever value" // replace PrivateGetter {get;}
};
Foo realBar = bar; // retrive the runtime instance
...
If you are looking for more information on Moles, start with the tutorials at http://research.microsoft.com/en-us/projects/pex/documentation.aspx.