Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mock context #34

Merged
merged 4 commits into from
Aug 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Methods with closure arguments and where clauses can now be mocked.
([#35](https://github.com/asomers/mockall/pull/35))

- Mocked static methods and free functions now use a Context object to manage
their expectations. The context object will validate call counts when it
drops, and clean up any leftover expectations. This makes it practical to
use mocked free functions from multiple test cases. The user still will most
likely need to provide his own synchronization to prevent such test cases
from running concurrently.
([#34](https://github.com/asomers/mockall/pull/34))

### Changed

- Better panic messages when an expectation fails its expected call count.
Expand Down
53 changes: 48 additions & 5 deletions mockall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,9 @@
//!
//! Mockall can also mock static methods. But be careful! The expectations are
//! global. If you want to use a static method in multiple tests, you must
//! provide your own synchronization.
//! provide your own synchronization. For ordinary methods, expectations are
//! set on the mock object. But static methods don't have any mock object.
//! Instead, you must create a `Context` object just to set their expectations.
//!
//! ```
//! # use mockall::*;
Expand All @@ -764,7 +766,8 @@
//! fn foo() -> u32;
//! }
//!
//! MockA::expect_foo().returning(|| 99);
//! let ctx = MockA::foo_context();
//! ctx.expect().returning(|| 99);
//! assert_eq!(99, MockA::foo());
//! ```
//!
Expand All @@ -787,7 +790,8 @@
//! }
//!
//! # fn main() {
//! MockFoo::expect_from_i32()
//! let ctx = MockFoo::from_i32_context();
//! ctx.expect()
//! .returning(|x| {
//! let mut mock = MockFoo::default();
//! mock.expect_foo()
Expand All @@ -812,12 +816,50 @@
//! }
//!
//! # fn main() {
//! MockFoo::<u32>::expect_new()
//! let ctx = MockFoo::<u32>::new_context();
//! ctx.expect()
//! .returning(|_| MockFoo::default());
//! let mock = MockFoo::<u32>::new(42u32);
//! # }
//! ```
//!
//! ### Context checkpoints
//!
//! The context object cleans up all expectations when it leaves scope. It also
//! has a `checkpoint` method that functions just like a mock object's
//! `checkpoint` method.
//!
//! ```should_panic
//! # use mockall::*;
//! #[automock]
//! pub trait A {
//! fn foo() -> u32;
//! }
//!
//! let ctx = MockA::foo_context();
//! ctx.expect()
//! .times(1)
//! .returning(|| 99);
//! ctx.checkpoint(); // Panics!
//! ```
//!
//! A mock object's checkpoint method works for static methods, too.
//!
//! ```should_panic
//! # use mockall::*;
//! #[automock]
//! pub trait A {
//! fn foo() -> u32;
//! }
//!
//! let mut mock = MockA::new();
//! let ctx = MockA::foo_context();
//! ctx.expect()
//! .times(1)
//! .returning(|| 99);
//! mock.checkpoint(); // Also panics!
//! ```
//!
//! One more thing: Mockall normally creates a zero-argument `new` method for
//! every mock struct. But it *won't* do that when mocking a struct that
//! already has a method named `new`.
Expand Down Expand Up @@ -860,7 +902,8 @@
//!
//! #[test]
//! fn test_foo() {
//! ffi::mock::expect_foo()
//! let ctx = ffi::mock::foo_context();
//! ctx.expect()
//! .returning(|x| i64::from(x + 1));
//! assert_eq!(43, do_stuff());
//! }
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_associated_type_constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ impl Foo {

#[test]
fn returning() {
MockFoo::expect_open().returning(|| {
let ctx = MockFoo::open_context();
ctx.expect().returning(|| {
struct Baz {}
impl Future for Baz {
type Item=MockFoo;
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_boxed_constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub trait A {

#[test]
fn returning() {
MockA::expect_new().returning(|| Box::new(MockA::default()));
let ctx = MockA::new_context();
ctx.expect().returning(|| Box::new(MockA::default()));
let _a: Box<MockA> = <MockA as A>::new();
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_constructor_impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ impl A {

#[test]
fn returning() {
MockA::expect_build().returning(|| {
let ctx = MockA::build_context();
ctx.expect().returning(|| {
struct Baz {}
impl Foo for Baz {}
Box::new(Baz{})
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_constructor_in_generic_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ trait Foo<T: 'static> {
fn return_once() {
let mock = MockFoo::<u32>::default();

MockFoo::<u32>::expect_new()
let ctx = MockFoo::<u32>::new_context();
ctx.expect()
.return_once(move |_| mock);

let _mock = MockFoo::new(5u32);
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_constructor_in_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ impl A {

#[test]
fn returning() {
MockA::expect_new().returning(MockA::default);
let ctx = MockA::new_context();
ctx.expect().returning(MockA::default);
let _a: MockA = MockA::new();
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_constructor_in_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub trait A {

#[test]
fn returning() {
MockA::expect_new().returning(MockA::default);
let ctx = MockA::new_context();
ctx.expect().returning(MockA::default);
let _a: MockA = <MockA as A>::new();
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_constructor_in_trait_with_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ trait Foo {
#[test]
fn return_once() {
let mock = MockFoo::default();
let ctx = MockFoo::new_context();

MockFoo::expect_new()
ctx.expect()
.return_once(|_| mock);

let _mock = MockFoo::new(5);
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_constructor_with_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ impl Foo {
#[test]
fn return_once() {
let mock = MockFoo::default();
let ctx = MockFoo::new_context();

MockFoo::expect_new()
ctx.expect()
.return_once(|_| mock);

let _mock = MockFoo::new(5);
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_foreign_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern "C" {

#[test]
fn returning() {
mock_ffi::expect_foo().returning(i64::from);
let ctx = mock_ffi::foo_context();
ctx.expect().returning(i64::from);
assert_eq!(42, unsafe{mock_ffi::foo(42)});
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_foreign_c_returning_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern "C" {

#[test]
fn returning() {
mock_ffi::expect_foo().returning(|| ());
let ctx = mock_ffi::foo_context();
ctx.expect().returning(|| ());
unsafe{mock_ffi::foo()};
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_foreign_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern "Rust" {

#[test]
fn returning() {
mock_ffi::expect_foo().returning(i64::from);
let ctx = mock_ffi::foo_context();
ctx.expect().returning(i64::from);
assert_eq!(42, unsafe{mock_ffi::foo(42)});
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_generic_constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ trait Foo {

#[test]
fn returning_once() {
MockFoo::expect_build::<i16>()
let ctx = MockFoo::build_context();
ctx.expect::<i16>()
.return_once(|_| MockFoo::default());

let _mock: MockFoo = MockFoo::build::<i16>(-1);
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_generic_static_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ trait A {

#[test]
fn returning() {
MockA::expect_bar::<i16>()
let ctx = MockA::bar_context();
ctx.expect::<i16>()
.returning(|_| 42);
assert_eq!(42, MockA::bar(-1i16));
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ trait Foo<T: 'static> {

#[test]
fn returning() {
MockFoo::<u32>::expect_foo()
let ctx = MockFoo::<u32>::foo_context();
ctx.expect()
.returning(|_| ());
MockFoo::foo(42u32);
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_many_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ fn return_var() {

#[test]
fn static_method_returning() {
MockManyArgs::expect_bean()
let ctx = MockManyArgs::bean_context();
ctx.expect()
.returning(|_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _| ());
MockManyArgs::bean(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
3 changes: 2 additions & 1 deletion mockall/tests/automock_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ cfg_if! {

#[test]
fn returning() {
mock_foo::expect_bar()
let ctx = mock_foo::bar_context();
ctx.expect()
.returning(|x| i64::from(x) + 1);
assert_eq!(5, mock_foo::bar(4));
}
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/automock_static_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ trait A {

#[test]
fn returning() {
MockA::expect_bar()
let ctx = MockA::bar_context();
ctx.expect()
.returning(|| 42);
assert_eq!(42, MockA::bar());
}
3 changes: 2 additions & 1 deletion mockall/tests/mock_closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ mod returning {

#[test]
fn static_method() {
MockFoo::expect_bean()
let ctx = MockFoo::bean_context();
ctx.expect()
.returning(|f| f(42));
assert_eq!(84, MockFoo::bean(|x| 2 * x));
}
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/mock_constructor_with_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ mock! {
fn returning_once() {
let mock = MockFoo::default();

MockFoo::expect_new()
let ctx = MockFoo::new_context();
ctx.expect()
.return_once(|_| mock);

let _mock = MockFoo::new(5);
Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/mock_generic_constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ mock! {

#[test]
fn returning_once() {
MockFoo::<i16>::expect_build()
let ctx = MockFoo::<i16>::build_context();
ctx.expect()
.return_once(MockFoo::<i16>::default);

let _mock: MockFoo<i16> = MockFoo::<i16>::build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ mock! {

#[test]
fn returning_once() {
MockFoo::<i16>::expect_build()
let ctx = MockFoo::<i16>::build_context();
ctx.expect()
.return_once(MockFoo::<i16>::default);

let _mock: MockFoo<i16> = MockFoo::<i16>::build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ mock! {

#[test]
fn returning() {
MockFoo::expect_make_g::<i16>()
let ctx = MockFoo::make_g_context();
ctx.expect::<i16>()
.returning(|t| G{t});
let g = MockFoo::make_g(42i16);
assert_eq!(g.t, 42i16);
Expand Down
Loading